Как интерпретируется определение функции после ее использования в вызове функции? - PullRequest
5 голосов
/ 11 марта 2010

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

int main()
{
        int e;
        prn(e);
        return 0;
}

void prn(double x,int t)
{
}

Почему этот код выдает следующие предупреждения и не содержит ошибок?

m.c:9: warning: conflicting types for ‘prn’  
m.c:5: note: previous implicit declaration of ‘prn’ was here

Разве это не должно выдавать ошибку "неопределенная функция"?

Ответы [ 2 ]

11 голосов
/ 11 марта 2010

В C99 он должен давать необъявленную функцию ошибка.

В C89 / 90 объявление функций не является обязательным. Если вызывается необъявленная функция, компилятор будет предполагать, что он возвращает int, и он передаст ей аргументы после того, как подвергнет их так называемым продвижениям аргументов по умолчанию . Другими словами, компилятор попытается вывести , что это за функция, от фактического вызова. Если позже функция определяется не так, как выводил компилятор, поведение не определено. Обычно компиляторы будут жаловаться на это с предупреждением.

Это то, что вы наблюдаете в вашем случае. Когда компилятор видит вызов prn(e), он предполагает, что prn является int prn(int) функцией. Но позже выясняется, что это на самом деле void prn(double, int). Несоответствие вызывает предупреждение.

В этом случае вам повезло в том смысле, что вызов необъявленной функции происходит в той же единице перевода, где определена функция. Таким образом, у компилятора есть возможность сравнить вызов и определение и выдать предупреждение о конфликте. Если бы prn было определено в каком-то другом модуле перевода, у компилятора никогда не будет возможности сравнить их, поэтому у вас будет полноценное неопределенное поведение в ваших руках.

6 голосов
/ 11 марта 2010

C89 имеет неявные объявления функций. Если вы используете функцию, не объявив ее, компилятор предполагает, что это int prn(). Когда это оказывается неверным (поскольку типы возвращаемых данных различаются), это дает вам знать.

Обратите внимание, что пустой список аргументов в объявлении функции означает «параметры не указаны», а не «нет параметров». Тогда вы должны убедиться, что входные параметры совпадают между вызывающим и вызываемым (что здесь не так), и вы можете вообще не получить помощи от компилятора.

В C99 эта «особенность» была удалена. Я думаю, что это было только в C89 для совместимости с древним кодом C. Было время, когда у С вообще не было прототипов функций, вам просто нужно было сделать это самостоятельно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...