Unistd.h и c99 в Linux

Этот простой .c файл:

#include <unistd.h>

void test() {
   char string[40];
   gethostname(string,40);
}

... при компиляции обычно работает нормально:

$ cc  -Wall -c -o tmp.o tmp.c
$

... но когда скомпилирован в режиме C99, выдается предупреждение:

$ cc -Wall -std=c99 -c -o tmp.o tmp.c 
tmp.c: In function `test':
tmp.c:5: warning: implicit declaration of function `gethostname'
$

Результирующий файл .o хорош, а ссылки работают. Я просто хотел бы избавиться от предупреждения. Я могу добиться этого в хакерском режиме, разместив объявления в моем собственном файле .h.

Что такое C99, что означает, что объявления в unistd.h не включаются? Можно ли это преодолеть, не отказываясь от достоинства C99?

Я вижу ту же проблему для других стандартных библиотек.

Ответ 1

Вам может потребоваться определить некоторые макросы в определенном порядке, чтобы получить прототип для gethostname()

От man gethostname:

Требования к макросам для тестирования функций glibc (см. feature_test_macros (7)):

   gethostname(): _BSD_SOURCE || _XOPEN_SOURCE >= 500
   sethostname(): _BSD_SOURCE || (_XOPEN_SOURCE && _XOPEN_SOURCE < 500)

Итак:

#define _BSD_SOURCE

#include <unistd.h>

void test() {
   char string[40];
   gethostname(string,40);
}

Детали gory:

Если вы не укажете опцию -std-c99, то features.h (которая неявно включена в unistd.h) по умолчанию будет устанавливать _BSD_SOURCE таким образом, чтобы прототип для gethostname() включался. Однако указание -std=c99 заставляет компилятор автоматически определять __STRICT_ANSI__, что в свою очередь заставляет features.h не определять _BSD_SOURCE, если только вы не навязываете его своим собственным определением макроса функции (как указано выше).

Ответ 2

gethostname( ) не является стандартной функцией C (она не упоминается нигде в стандарте C99), поэтому при компиляции стандарту символ не задан.

Если вы используете инструментальную цепочку gcc, используйте -std=gnu99, и вы получите нужное поведение.

В качестве альтернативы, глядя на <features.h>, вы можете использовать -D_GNU_SOURCE или -D_XOPEN_SOURCE=500 для получения желаемого поведения.

Ответ 3

Прочтите man gethostname. Он говорит в требованиях к макросам проверки функций, что _BSD_SOURCE (или _XOPEN_SOURCE>500) требуется для вытаскивания gethostname из unistd.h.

Далее прочитайте man feature_test_macros. Вы обнаружите, что -std=c99 включается __STRICT_ANSI__, который отключается _BSD_SOURCE. Это означает, что вы не можете получить gethostname из unistd.h, если вы еще не определили _BSD_SOURCE. Обычно я использую _GNU_SOURCE в моей командной строке (т.е. gcc -D_GNU_SOURCE -std=c99 file.c) для большинства вещей, которая также включает _BSD_SOURCE.

P.S. На странице руководства содержится примерная программа, которая может печатать текущие ft-макросы. Вы можете скомпилировать и запустить его для некоторых параметров компилятора.