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

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

Стенограмма сеанса:

>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
4b9b3361

Ответ 1

В режиме строгого соответствия (это означает "теоретически" ) вы вызываете поведение undefined (что плохо) при вызове функции, которая принимает переменное количество аргументов без объявления прототипа функции в области видимости. Это означает, что компилятору разрешено делать все, что ему нравится, с программой, которая использует 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() были определены с эллипсисом, этот прототип понадобился бы в теории! )

Ответ 2

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

int printf();

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

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

Ответ 3

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

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