Является ли это сомнительным использование объявления не-прототипа функции?

Действительно ли это C (C99) код?

int f(); int g(int x) { if (x<0) return f(x); else return f(x,x); } 

Очевидно, что программа имеет неопределенное поведение, если g когда-либо вызывается с отрицательным аргументом, а f не является функцией, которая принимает один аргумент int , или если g когда-либо вызывается с неотрицательным аргументом, а f не является функцией, которая принимает два int аргументы. Но иначе?

Рассмотрим в качестве примера этот отдельный исходный файл, который вызывает g из приведенного выше и предоставляет f :

 int g(); #ifdef FOO int f(int a, int b) { return a+b; } int main() { return g(1); } #else int f(int a) { return a; } int main() { return g(-1); } #endif 

Давайте попробуем наоборот: почему это недействительно? , Я действительно не могу найти никаких аргументов или правил, запрещающих вышеуказанный код. Вызов функции в соответствующей другой ветке никогда не выполняется (хотя обсуждение в комментариях указывает, что это не так просто!).

C99 (6.5.2.2 Функциональные вызовы, пункт 8) говорит, что количество и типы параметров и аргументов «не сравниваются», если определение функции не имеет прототипа.

Я видел это (ab), используемое в дикой природе с указателями функций. Массив void (*)() содержал указатели функций void (*)(struct Client *) и void (*)(struct Client *, int parc, char *parv[]) . На основе индекса массива код передал дополнительные параметры или нет.

В этом случае у компилятора нет (разумного) способа проверить количество параметров заранее, даже если у него есть все соответствующие коды.

Я думаю, что это грязный код, и я исправил этот конкретный экземпляр.

Я бы согласился с тем, что он действителен до тех пор, пока неправильный вызов функции никогда не будет оцениваться абстрактной машиной C.

Существует еще один, более простой способ прийти к вашему выводу о компоновщике, хотя: поскольку это разрешено:

 int f(); int (*fp)() = f; 

Линкер должен иметь возможность найти адрес f() не зная его фактического определения. Поэтому его символ должен быть определен без знания фактического определения.

Что, если это f(int x, ...) и он смотрит на знак своего первого аргумента, чтобы узнать, сколько (0 или 1) varargs оно получило?

Это действительно (ну, это может зависеть от того, какой стандарт вы используете). Вы должны прочитать что-то о вызовах конвенций .

В принципе, если f принимает один или никаких аргументов, я бы не ожидал никаких проблем.
Если f принимает два или более аргумента, можно ожидать, что другие аргументы (отличные от первого) будут иметь нежелательные (по-видимому, случайные) значения.

Рассмотрим этот fragment кода:

 int f(int x, int y); int g(int x) { int k; //No value if (x<0) return f(x, k); else return f(x, x); } 

Конечно, это плохая идея. Вы должны явно указать все аргументы.

Вы также можете использовать int f(void); явно объявить, что f не принимает аргументов.

Имейте в виду, что перегрузка функций C ++ может вызвать проблемы, но я предполагаю, что это не вызывает беспокойства, так как вы отметили свой вопрос c . Кроме того, некоторые вызовы могут вызвать серьезные проблемы.