Подтвердить что ты не робот

Неявные декларации функций в C

Что подразумевается под термином "неявное объявление функции". Вызов стандартной библиотечной функции без включения соответствующего файла заголовка вызывает предупреждение, как в случае

int main(){
  printf("How is this not an error ?");
  return 0;
}

Не следует использовать функцию без объявления об ошибке? Пожалуйста, объясните подробно. Я искал этот сайт и нашел похожие вопросы, но не смог найти окончательного ответа. Большинство ответов говорили о включении файла заголовка, чтобы избавиться от предупреждения. Но я хочу знать, как это не ошибка.

4b9b3361

Ответ 1

Это следует считать ошибкой. Но C - древний язык, поэтому это только предупреждение.
Компиляция с помощью -Werror (gcc) устраняет эту проблему.

Когда C не находит объявление, он принимает это неявное объявление: int f();, что означает, что функция может получать все, что вы ему даете, и возвращает целое число. Если это происходит достаточно близко (и в случае printf, это так), тогда все может работать. В некоторых случаях (например, функция фактически возвращает указатель, а указатели больше, чем int), это может вызвать настоящую проблему.

Обратите внимание, что это было исправлено в новых стандартах C (C99, C11). В этих стандартах это ошибка. Однако gcc не выполняет эти стандарты по умолчанию, поэтому вы все равно получите предупреждение.

Ответ 2

Неявные объявления недействительны в C.

C99 удалил эту функцию (присутствует в C89).

gcc выбирает только предупреждение по умолчанию с -std=c99, но компилятор имеет право отказаться от перевода такой программы.

Ответ 3

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

В частности, C не требует, чтобы функции были объявлены до их использования. Если вы вызываете функцию без объявления ее, использование функции становится ее (неявным) объявлением. В простом тесте я просто запускал, это только предупреждение в случае встроенных функций библиотеки, таких как printf (по крайней мере, в GCC), но для случайных функций он будет компилироваться просто отлично.

Конечно, когда вы пытаетесь установить ссылку и не можете найти foo, тогда вы получите сообщение об ошибке.

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

Ответ 4

Из-за исторических причин, возвращающихся к самой первой версии C, предполагается, что функции имеют неявное определение int function(int arg1, int arg2, int arg3, etc).

Изменить: нет, я ошибался в отношении int для аргументов. Вместо этого он передает любой тип аргумента. Таким образом, это может быть int или double или char*. Без прототипа компилятор будет передавать любой размер аргумента и вызываемой функции лучше использовать правильный тип аргумента для его получения.

Подробнее см. K&R C.

Ответ 5

Чтобы завершить изображение, так как -Werror может считаться слишком "инвазивным",
для gcc (и llvm) более точным решением является преобразование именно этого предупреждения в ошибку с помощью опции:

-Werror=implicit-function-declaration

См. Сделать gcc предупреждение об ошибке?

Относительно общего использования -Werror: Конечно, наличие предупреждающего кода рекомендуется, но на каком-то этапе разработки он может замедлить прототипирование.

Ответ 6

Неявно объявленная функция - это та, которая не имеет ни прототипа, ни определения, но называется где-то в коде. Из-за этого компилятор не может проверить, что это предполагаемое использование функции (совпадают ли счетчик и тип аргументов). Разрешение ссылок на него выполняется после компиляции во время соединения (как и со всеми другими глобальными символами), поэтому технически это не проблема пропустить прототип.

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

Ошибки могут возникать при вызове функции с аргументами неправильного типа или подсчета. Наиболее вероятным проявлением этого является повреждение стека.

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