Почему #include <stdio.h> не требуется использовать printf()?

StackOverflow https://stackoverflow.com/questions/336814

  •  22-07-2019
  •  | 
  •  

Вопрос

Стенограмма заседания:

>type lookma.c
int main() {
  printf("%s", "no stdio.h");
}

>cl lookma.c
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 14.00.50727.762 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

lookma.c
Microsoft (R) Incremental Linker Version 8.00.50727.762
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:lookma.exe
lookma.obj

>lookma
no stdio.h
Это было полезно?

Решение

В режиме строгого соответствия (что означает "теоретически") вы вызываете неопределенное поведение (что плохо) при вызове функции, которая принимает переменное количество аргументов без объявления прототипа функции в области видимости.Это означает, что компилятору разрешено делать все, что ему заблагорассудится, с программой, которая использует printf() без прототипа из #include <stdio.h> или эквивалентное заявление."Все, что ему нравится" включает корректную работу в качестве одного из вариантов;похоже, это вариант, выбранный в вашем примере.

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

Как было указано qrdl, функция была найдена, потому что компилятор C связывается с библиотекой C.

Обратите внимание, что комментарий Криса Янга о C99 и "неявном int" точен, но правило о том, что "функции с переменными аргументами должны иметь прототип в области видимости", применимо как к C89, так и к C99.Большинство компиляторов по умолчанию не работают в режиме строгой совместимости с C99, потому что существует слишком много кода, который не компилировался бы подобным образом.

Крис Янг прокомментировал:

Чтобы внести ясность, мой комментарий касался удаления неявных объявлений C99.Говоря "неявный int", я думаю, вы имеете в виду функцию C89, разрешающую такие объявления, как foo(void);чтобы означать int foo(void);, что-то C99 также удалено.

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

  • удалить неявный int
  • удалить объявление неявной функции

Я недостаточно ясно мыслил (и, следовательно, писал).Тем не менее, как C89, так и C99 требуют прототипа в области видимости для функций, которые принимают переменное количество аргументов.

Чтобы проиллюстрировать:

extern int pqr();
int main(void)
{
    int i = pqr(1, 3);
    return i;
}

Без первой строки это правильный фрагмент C89 с неявным объявлением функции pqr() как функция, которая возвращает целое число (с неуказанными аргументами).Если первая строка заменена на extern pqr();, тогда это правильный фрагмент C89 с явным объявлением pqr() как функция, которая возвращает целое число (с неопределенными аргументами), но возвращаемый тип 'неявный int'.Как написано, функция явно объявлена и имеет явное int возвращаемый тип - но он по-прежнему имеет неопределенные аргументы.Я считаю, что это допустимо C99 - хотя и не совсем желательно.Конечно, GCC (3.4.4) принимает это вместе с параметрами '-std=c99 -pedantic".В идеале объявление функции должно включать полный прототип.(И, если pqr() были бы определены с многоточием, потребовался бы этот прототип теоретически!)

Другие советы

Вы изначально пометили этот C ++, но, похоже, это программа на C. C автоматически предоставит неявное объявление для функции, если в области нет прототипа (например, из-за пропуска #include < stdio.h >). Неявное объявление будет следующим:

int printf();

Это означает, что printf - это функция, которая возвращает int и может принимать любое количество аргументов. Этот прототип сработал для вашего звонка. Вы должны #include < stdio.h >

Наконец, я должен добавить, что текущий стандарт C (ISO / IEC 9899: 1999 или разговорный «C99») не разрешает неявные объявления, и эта программа не будет соответствовать. Неявные объявления были удалены. Я считаю, что ваш компилятор не поддерживает C99. C ++ также требует правильных прототипов и не делает неявных объявлений.

printf () находится в стандартной библиотеке C, и компоновщик всегда связывает стандартную библиотеку с вашим исполняемым файлом, поэтому любые стандартные функции будут найдены и проблем с компоновкой не будет.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top