Что произойдет, если я не включу файлы заголовков

Что произойдет, если я не включу файлы заголовков при запуске программы ac? Я знаю, что получаю предупреждения, но программы работают отлично.

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

Я знаю, что получаю предупреждения, но программы работают отлично.

Это неудачное наследие pre-ANSI C: язык не требует прототипов функций, поэтому стандарт C позволяет ему по сей день (как правило, можно получить предупреждение, чтобы найти функции, называемые без прототипа).

Когда вы вызываете функцию без прототипа, компилятор C делает предположения о вызываемой функции:

  • Возвращаемый тип функции считается int
  • Предполагается, что все параметры объявлены (т.е. нет ... vararg stuff)
  • Все параметры считаются тем, что вы передаете после промо-акций по умолчанию, и так далее.

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

До стандарта ANSI C 1989 года не было возможности объявить функцию и указать типы ее параметров. Вам просто нужно было быть очень осторожным, чтобы каждый вызов соответствовал вызываемой функции, без предупреждения от компилятора, если вы ошибаетесь (например, передаете int в sqrt() ). При отсутствии видимого объявления любая функция, которую вы вызываете, должна была возвращать int ; это было правило «неявное int». Многие стандартные функции возвращают int , поэтому вы часто можете уйти с отсутствием #include .

Стандарт ANSI C 1989 года (который также, по существу, стандарт ISO C 1990 года) вводил прототипы, но не делал их обязательными (и они все еще не являются). Поэтому, если вы позвоните

 int c = getchar(); 

он будет работать, потому что getchar() возвращает int .

В стандарте ISO ISO 1999 года было исключено неявное правило int и было запрещено его использование (фактически нарушение ограничений ) для вызова функции без видимого объявления. Поэтому, если вы вызываете стандартную функцию без обязательного #include , компилятор, соответствующий C99, должен выдать диагностику (которая может быть просто предупреждением). Объявления непропротеированных функций (те, которые не указывают типы аргументов) по-прежнему являются законными, но считаются устаревшими.

(В 2011 году стандарт ISO C не сильно изменился в этой конкретной области).

Но есть еще много кода, который был написан для компиляторов C90, и большинство современных компиляторов по-прежнему поддерживают старый стандарт.

Поэтому, если вы вызываете стандартную функцию без обязательного #include , то, вероятно, произойдет следующее: (а) компилятор предупредит вас о отсутствующем объявлении, и (б) он предположит, что функция возвращает int и принимает любое число и тип (ы) аргументов, которые вы фактически передали ему (также учитывающий продвижение типа, например, short to int и float чтобы double ). Если звонок правильный, и если вы компилируете его, то ваш код, скорее всего, будет работать, но вы будете иметь еще одну вещь, о которой стоит беспокоиться, если это не удастся, возможно, по какой-то причине.

Вариадические функции, такие как printf – это другое дело. Даже в C89 / C90 вызов printf без видимого прототипа имел неопределенное поведение. Компилятор может использовать совершенно другое соглашение о вызовах для вариативных функций, поэтому printf("hello") и puts("hello") могут генерировать совершенно другой код. Но, опять же, для совместимости со старым кодом большинство компиляторов используют совместимое соглашение о вызове, поэтому, например, первая программа «hello world» в K & R1, вероятно, все еще будет компилироваться и запускаться.

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

Итак, что на самом деле произойдет, если вы вызовете стандартную функцию без соответствующего #include ?

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

В принципе, любой компилятор, который соответствует C99 или новее, может отклонить вашу программу с фатальным сообщением об ошибке. (gcc будет вести себя таким образом с -std=c99 -pedantic-errors ). На практике большинство компиляторов просто печатает предупреждение. Вызов, вероятно, будет работать, если функция вернет int (или если вы проигнорируете результат), и если вы вернете все типы аргументов. Если вызов неверен, компилятор не сможет распечатать хорошую диагностику. Если функция не возвращает int , компилятор, вероятно, предположит, что это так, и вы получите результаты мусора или даже сбой вашей программы.

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

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

Прежде всего: просто включите их.

Если вы не используете компилятор, будет использоваться прототип по умолчанию для незаявленных функций, а именно:

 int functionName(int argument); 

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

Есть много вещей, которые вы не можете сделать, если не оставляете заголовки:

(Я надеюсь получить немного больше от комментариев, так как моя память не работает на этом …)

  • Вы не можете использовать какие-либо macros, определенные в заголовках. Это может быть значительным.
  • Компилятор не может проверить, правильно ли вы вызываете функции, поскольку заголовки определяют для него свои параметры.

Для совместимости со старой программой компиляторы C могут компилировать вызывающие код функции, которые не были объявлены, при условии, что параметры и возвращаемое значение имеют тип int . Что может случиться? Посмотрите, например, на этот вопрос: беспокоящий преобразование строки в длинную часть C. Я думаю, что это отличная иллюстрация проблем, с которыми вы можете столкнуться, если вы не включаете необходимые заголовки и поэтому не объявляете функции, которые используете. Что случилось с парнем, он пытался использовать atoll без включения stdlib.h где объявлен atoll :

 char s[30] = { "115" }; long long t = atoll(s); printf("Value is: %lld\n", t); 

Удивительно, но это напечатано 0 , а не 115 , как и ожидалось! Зачем? Поскольку компилятор не видел объявления atoll и предположил, что это возвращаемое значение является int , и поэтому выбрала только часть значения, оставшегося на стеке функцией, другими словами, возвращаемое значение было усечено.

Вот почему из соображений рекомендуется скомпилировать ваш код с помощью функции -Wall (все предупреждения -Wall ).