Не включая 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).

Другие вопросы по тегам