Почему я могу успешно скомпилировать программу, даже если файл заголовка отсутствует?

#c #compilation #strtok

#c #Сборник #strtok

Вопрос:

Я обнаружил странную проблему, когда изучал функцию «strtok». Сначала я пропустил файл заголовка при написании демонстрационной программы следующим образом:

 /* strtok example */
#include <stdio.h>
//#include <string.h> // the header file I've missed at first

int main ()
{
    char str[] ="- This, a sample string.";
    char * pch;
    printf ("Splitting string "%s" into tokens:n",str);
    pch = strtok (str," ,.-");
    while (pch != NULL)
    {   
        printf ("%sn",pch);
        pch = strtok (NULL, " ,.-");
    }   
    return 0;
}
  

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

Мой вопрос в том, почему компилятор не диагностировал никаких ошибок при первой компиляции. Я скомпилировал ее под Mac OS X с помощью gcc4.2.1.

Комментарии:

1. ошибочное прямое объявление приводит к умолчанию …. определение who ускользает от меня atm

Ответ №1:

В C функциям разрешалось не иметь прототипов (объявлений). При вызове таких функций преобразования параметров не будет. Например.:

 f(0);
  

вызовет функцию с именем f с параметром (int)0 , даже если f он не был объявлен. Это приводит к неопределенному поведению (… segfaults …), когда фактическое определение f (в другом .c файле или в библиотеке) было, например. int f(char*) или int f(long) . Это не очень хорошая практика, но она сохраняется для обеспечения обратной совместимости с исходным C.

Когда прототип присутствует, компилятор автоматически преобразует параметр в требуемые типы (возможно, выдает ошибку) на сайте вызова.

PS: не поймите меня неправильно, int это значение по умолчанию. То, что на самом деле вызывает компилятор, полностью зависит от параметров вызова. Например. f(1.1) будет соответствовать с void f(double) , f("string") с f(char*) .

Комментарии:

1. 1. прошло так много времени, что я не мог вспомнить, что было по умолчанию! 🙂

2. Убедительный ответ, но компилятор C может фактически вывести правильную сигнатуру strtok() в данном фрагменте кода. Никаких преобразований не требуется.

3. @HansPassant: нет, если NULL определено как 0 (что является законным в соответствии со стандартом), а указатели имеют ширину 64 бита.

Ответ №2:

Мой вопрос в том, почему компилятор не выдал никакого сообщения об ошибке при первой компиляции.

Потому что вы не скомпилировали с -Wall -Wextra . Для недавно написанного современного кода вы должны делать это как само собой разумеющееся.

Комментарии:

1. -W Флаги (за исключением -Werror и, возможно, еще 1 или 2) не генерируют ошибок. Они генерируют предупреждение, и компиляция может быть успешной в любом случае 🙂