Intereting Posts
Условный переход или перемещение зависят от неинициализированного значения (значений) добавление нового пользователя в список в программе c Автоматический переупорядочивание полей в структурах C, чтобы избежать заполнения Как скомпилировать и запустить программу C / C ++ в системе Android Чтение пакетов RTCP с IP-камеры с использованием FFMPEG Как получить символ новой строки из scanf, даже если это единственный вход Чтение символа с помощью scanf () Что означает # прагма в C? printf () форматирование для hex относительно использования программы ac для преобразования файла csv в конкретный формат использование прототипа функции в функции без указателя C pow () не работает с переменным показателем Когда malloc возвращает NULL в безголовой среде? Бит popcount для большого буфера, с процессором Core 2 (SSSE3) Почему язык C не поддерживает массив столбцов?

C программа без заголовка

Я пишу программу «hello world» в C.

void main() { printf("Hello World"); } // note that I haven't included any header file 

Программа компилируется с предупреждением как

 vikram@vikram-Studio-XPS-1645:~$ gcc hello.c hello.c: In function 'main': hello.c:2:2: warning: incompatible implicit declaration of built-in function 'printf' vikram@vikram-Studio-XPS-1645:~$ ./a.out Hello Worldvikram@vikram-Studio-XPS-1645:~$ 

Как это возможно? Как ОС связывает библиотеку без включения какого-либо заголовка?

Компилятор строит ваш исходный файл со ссылкой на функцию printf() , не зная, какие аргументы он фактически принимает или каков его тип возврата. Сгенерированная assembly содержит push -адрес строки "Hello World" в области статических данных вашей программы, а затем call printf .

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

Короче говоря: #include правильные заголовки, чтобы получить правильные объявления для функций, которые вы используете, потому что этот вид неявного объявления устарел, потому что он подвержен ошибкам.

Функция printf находится в библиотеке C ( libc в вашем случае), которая неявно связана (на самом деле gcc имеет встроенный printf, но не находится за пределами точки).

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

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

В C, если вы используете стандартную библиотечную функцию, вы должны включить стандартный заголовок, где объявлена ​​функция. Для printf вы должны включить заголовочный файл stdio.h .

В C89 (и GNU C89, который является языком по умолчанию в gcc ), объявление функции иногда может быть опущено, поскольку существует функция, называемая объявлением неявной функции: когда используется идентификатор функции foo и функция не объявлена, реализация будет использовать это заявление:

  /* foo is a function with an unspecified number of arguments */ extern int foo(); 

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

Вот что говорит C89 / C90:

(C90, 6.7.1) «Если функция, принимающая переменное количество аргументов, определяется без списка типов параметров, который заканчивается нолью многоточием, поведение не определено.

Так что gcc достаточно любезен для компиляции даже в C89 и GNU C89: компилятор может отказаться от компиляции.

Также отметим, что

 void main() { ... } 

не является допустимым определением для main (по крайней мере, для хостинговых реализаций, который, вероятно, относится к вашему делу).

Если ваша основная функция не принимает никаких аргументов, используйте это правильное определение:

 int main(void) { ... } 

Обычно заголовок 1 содержит только объявления функций, символические константы и определения макросов; он обычно не включает определения функций.

Все stdio.h дает вам объявление прототипа для printf :

 int printf(const char * restrict format, ...); // as of C99 

Реализация printf находится в отдельном файле библиотеки, с которым связаны ваши кодовые ссылки.

Ваш код «работает» по двум причинам:

  1. В C89 и более ранних версиях, если компилятор видит вызов функции перед объявлением или определением этой функции, он будет считать, что функция возвращает int и принимает неуказанное количество параметров;

  2. Реализация printf возвращает int , и вы передали аргумент, который просто оказывается совместимым с тем, что ожидает реализация printf для первого аргумента.

И чтобы повторять то, что говорят все остальные, используйте int main(void) или int main(int argc, char **argv) ; если ваша компиляторная документация явно не указала void main() как юридическую подпись, использование ее вызовет неопределенное поведение (что означает, что все из вашего кода работает без каких-либо очевидных проблем при сбое при выходе из-за невозможности полной загрузки).


  1. Я говорю «обычно»; Я столкнулся с некоторыми заголовками, содержащими код, но обычно они писали люди, которые не знали, что они делают. Там могут быть очень редкие случаи, когда размещение кода в заголовке оправдано, но, как правило, это плохая практика.

hello.c: 2: 2: warning: несовместимое неявное объявление встроенной функции ‘printf’

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

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