unistd.h和c99在Linux上的作用是什么?

13

这个简单的 .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文件中放置声明来以hacky的方式实现。

C99有什么特点导致unistd.h中的声明没有被包含进来?是否可以解决这个问题,而不失去C99的优势?

我在其他标准库中也看到了同样的问题。

3个回答

20
你可能需要以特定方式定义一些宏才能获得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);
}

具体细节如下:

如果您没有指定-std-c99选项,则features.h(隐含地被unistd.h包含)将默认设置为以这样的方式设置_BSD_SOURCE,以便包括gethostname()的原型。 然而,指定-std=c99会导致编译器自动定义__STRICT_ANSI__,从而导致features.h不定义_BSD_SOURCE,除非您使用自己的特性宏定义强制它(如上所述)。


1
对于一个答案加1分,对于#define _BSD_SOURCE减10分。请使用#define _XOPEN_SOURCE 500或者更好的方式在构建链中:cc -D_XOPEN_SOURCE=500 ...。如果需要任何形式的可移植性,那么这是必须的。 - Dummy00001
就像我对Luther的回复一样,我的Red Hat系统上的man gethostname没有提到Feature Test Macro Requirements。有人知道为什么吗? - slim

12

gethostname() 不是标准 C 函数(在 C99 标准中没有提到),因此在编译为标准时,该符号不会被正确定义。

如果您使用的是 gcc 工具链,则可以使用 -std=gnu99,就能得到所需的行为。

或者,查看 <features.h>,似乎可以使用 -D_GNU_SOURCE-D_XOPEN_SOURCE=500 来获得所需的行为。


虽然我接受了不同的答案,但实际上我使用的是“-std=gnu99”。谢谢。 - slim
刚遇到了这个问题,我也选择了 -std=gnu99 - Cubbi

5

阅读 man gethostname。在特性测试宏要求中,需要使用_BSD_SOURCE(或_XOPEN_SOURCE>500)从unistd.h中获取gethostname。

接下来阅读man feature_test_macros。您会发现-std=c99打开了__STRICT_ANSI__,这又关闭了_BSD_SOURCE。这意味着您无法从unistd.h获取gethostname,除非您再次定义_BSD_SOURCE。我通常将_GNU_SOURCE放在命令行上(即gcc -D_GNU_SOURCE -std=c99 file.c)用于大多数事情,这也打开了_BSD_SOURCE

P.S.手册页面包含一个示例程序,可以打印当前的ft-macros。您可以编译并运行它以获取一些编译器设置。


我的Redhat系统中没有man gethostname的任何内容。你的系统是什么?我需要安装额外的手册页吗? - slim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接