Не включая stdlib.h не выдает никакой ошибки компилятора!
Надеюсь, это очень простой вопрос. Ниже приводится Cgg (test.c), который у меня есть.
#include <stdio.h>
//#include <stdlib.h>
int main (int argc, char *argv[]) {
int intValue = atoi("1");
double doubleValue = atof("2");
fprintf(stdout,"The intValue is %d and the doubleValue is %g\n", intValue, doubleValue);
return 0;
}
Обратите внимание, что я использую atoi () и atof () из stdlib.h, но я не включаю этот заголовочный файл. Я компилирую pgm (gcc test.c) и не получаю ошибки компилятора!
Я запускаю pgm (./a.out), и здесь вывод, который является неправильным.
The intValue is 1 and the doubleValue is 0
Теперь я включил stdlib.h (удалив комментарии перед #include), перекомпилировал и снова запустил. На этот раз я получаю правильный вывод:
The intValue is 1 and the doubleValue is 2
Почему же компилятор не жаловался на то, что не включил stdlib.h, и все же позволил мне использовать функции atoi (), atof ()?
Моя информация о gcc:
$ gcc --version
gcc (GCC) 4.1.2 20070925 (Red Hat 4.1.2-27)
Любые мысли приветствуются!
5 ответов
По историческим причинам - в частности, совместимость с очень старыми программами на C (до C89) - использование функции без ее предварительного объявления только вызывает предупреждение от GCC, а не ошибку. Но тип возврата такой функции предполагается int
не double
Именно поэтому программа выполняется некорректно.
Если вы используете -Wall
в командной строке вы получаете диагностику:
$ gcc -Wall test.c
test.c: In function ‘main’:
test.c:5: warning: implicit declaration of function ‘atoi’
test.c:6: warning: implicit declaration of function ‘atof’
Вы должны использовать -Wall
в основном всегда. Другие очень полезные параметры предупреждения для нового кода: -Wextra
, -Wstrict-prototypes
, -Wmissing-prototypes
, -pedantic
, а также -Wwrite-strings
, но по сравнению с -Wall
у них намного выше ложные положительные показатели.
Тангенциально: никогда не используйте atoi
ни atof
они скрывают ошибки ввода. использование strtol
а также strtod
вместо.
Если вы не укажете иначе, я верю, что компилятор C просто догадывается, что необъявленные функции принимают форму extern int foo()
, Вот почему atoi
работает и atof
не делает. Какие флаги компилятора вы использовали? Я предлагаю использовать -Wall
включить кучу предупреждений gcc, которые должны включать ссылки на необъявленные функции.
C позволяет вам вызывать функцию без объявления этой функции.
Предполагается, что функция возвращает int
и аргументы будут переданы с использованием промо-акций по умолчанию. Если они не соответствуют тому, что на самом деле ожидает функция, вы получите неопределенное поведение.
Компиляторы часто предупреждают об этом случае, но не всегда (и это также будет зависеть от конфигурации компилятора).
В C, когда вы используете функцию, которая не была объявлена, предполагается, что у нее есть прототип по умолчанию:
int FUNCTION_NAME();
Обратите внимание, что в C использование () в качестве прототипа означает, что он принимает любые аргументы.
Если вы скомпилируете с флагом -Wall (я рекомендую вам всегда использовать этот флаг, поскольку он разрешает все рекомендуемые предупреждения), вы получите предупреждение (не об ошибке), сообщающее, что вы используете необъявленную функцию.
К сожалению, C не требует, чтобы функции были прототипированы (или даже объявлены) перед использованием - но без прототипа он автоматически делает определенные предположения о функции. Одним из них является то, что он возвращает int. В твоем случае, atoi
возвращает int
, так что работает правильно. atof
нет, поэтому он не работает правильно. Не имея прототипа / объявления, вы получаете неопределенное поведение - как правило, в конечном итоге он извлекает любое значение в регистре, где int
будет обычно возвращаться, и с помощью этого. Похоже, что в вашем конкретном случае это будет ноль, но это может быть просто что-то еще.
Это одна из причин, по которой многие люди настаивают на том, что "C++ - лучший C" - C++ требует, чтобы все функции были объявлены перед использованием, и, кроме того, вы также указываете типы всех (не вариадных) параметров (например, C++). объявление функции похоже на прототип C, а не на объявление C).