【问题标题】:Why does gcc not complain about htons() but complains about getaddrinfo() when compiled with -std=c99?为什么 gcc 在使用 -std=c99 编译时不抱怨 htons() 但抱怨 getaddrinfo()?
【发布时间】:2017-01-17 12:03:42
【问题描述】:

即使使用-std=c99 编译,以下程序也能正常编译和运行。

#include <stdio.h>
#include <arpa/inet.h>

int main()
{
    printf("%d\n", htons(1));
}

这是输出。

$ gcc -std=c99 foo.c && ./a.out
256

但是下面的程序会导致警告和错误。

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int main()
{
    struct addrinfo *res;
    getaddrinfo("localhost", NULL, NULL, &res);
    printf("%d\n", res->ai_flags);
}

这是警告和错误。

$ gcc -std=c99 bar.c
bar.c: In function ‘main’:
bar.c:9:5: warning: implicit declaration of function ‘getaddrinfo’ [-Wimplicit-function-declaration]
     getaddrinfo("localhost", NULL, NULL, &res);
     ^
bar.c:10:23: error: dereferencing pointer to incomplete type
     printf("%d\n", res->ai_flags);

为什么编译器在用-std=c99编译时不抱怨htons(),而是抱怨getaddrinfo()

我在 Debian 8.3 系统上使用 gcc 4.9.2 编译此代码。

【问题讨论】:

  • 我对这些库一无所知,但似乎是一些库安装问题。
  • @Lundin 这不是库安装问题。我没有安装这些库。它是系统自带的。这是关于 C99 与 POSIX 的问题,因为我已经在这个问题中标记了。如果我从编译器选项中省略-std=c99,第二个代码示例将编译得很好。
  • getaddrinfo 在 1999 年不存在
  • 如果添加-D_POSIX_C_SOURCE=200809L 会发生什么?在严格的 c99 模式下,标头可能有一个隐藏这些声明的条件。
  • @stark htons 也没有。那为什么会编译呢?

标签: c posix c99


【解决方案1】:

来自 Linux man pages for glibc

POSIX.1-2001。 htons()

POSIX.1-2001、POSIX.1-2008。 getaddrinfo() 函数已记录在案 在 RFC 2553 中。

从 glibc 2.22 开始:_POSIX_C_SOURCE >= 201112L

Glibc 2.21 及更早版本:_POSIX_C_SOURCE

要获得getaddrinfo() 的原型,您需要在包含标头之前指定要使用的POSIX 版本,例如:

#define _POSIX_C_SOURCE 201112L

RFC 2553 将 IPv6 支持添加到套接字接口。添加意味着添加了新结构。 由于并非所有 plkatforms 都同时实现了新内容,因此需要指定您需要哪些版本的接口来处理已更改的内容。 htons 在所有版本中都是一样的,所以它不关心你请求什么版本。 getaddrinfo 由于 RFC 2553 已更改,因此您需要指定您想要/(可以处理)更改的版本。

如 cmets 中所述,_POSIX_C_SOURCE 所需的值因平台而异。似乎对于 RHEL6 上的 gcc,指定 _POSIX_SOURCE 或 _POSIX_C_SOURCE >= 1 就足够了。

如果有人能确认 _POSIX_SOURCE 是否是在任何 POSIX 系统上获取getaddrinfo 原型的可移植方式,那就太好了。

【讨论】:

  • 或者,通过-D_POSIX_C_SOURCE=201112L 将其传递给编译器,而不将其放在文件的开头。
  • 为什么推荐201112L 的特定值用于_POSIX_C_SOURCE?在我的系统上,我看到/usr/include/features.h_POSIX_C_SOURCE 定义为200809L(也通过使用gcc -E 预处理_POSIX_C_SOURCE 来确认)。另外,为什么不推荐像#define _POSIX_SOURCE 1 这样似乎也有效的东西?
  • 你知道为什么getaddrinfo() 需要这些宏定义而htons() 不需要吗?
  • @LoneLearner 谷歌搜索时我碰巧找到的手册页给出了值 201112L (我在答案中添加了一个链接)。似乎所需的值可能因平台而异。我已经更新了我的答案。
  • man getaddrinfo 中的值 201112L 看起来像是手册页中的拼写错误,因为没有名为 POSIX.1-2011 的此类 POSIX 标准。 man feature_test_macros 似乎表明该值应为200112L。第二个链接中没有名为201112L 的值。
【解决方案2】:

问题不在getaddrinfo - 它在struct addrinfogettaddrinfo 的隐式声明是一个警告,而不是错误。 struct addrinfo 未声明,是错误。

结构在netdb.h 中声明,但隐藏在ifdef __USE_POSIX 下。有评论:

/* 来自 POSIX.1g 的扩展。 */

htons 不存在这样的 ifdef

【讨论】:

  • 顺便说一句,对于htons 的隐式声明,我没有收到任何警告。 gcc -std=c99 -pedantic -Wall -Wextra foo.c 编译成功,没有任何警告。
  • 是的,那是因为它实际上是声明的。我假设您完全忘记了标题。我已经删除了我的答案的那部分。
  • 所以这让我回到了这个问题:为什么这些东西以这种方式排列,即为什么用 -std=c99 htons() 声明但 getaddrinfo() 不是即使是否包含必要的标题?
  • 请注意,如果返回类型不是int,那么隐式声明就会成为问题。
  • 这就是为什么我认为没有导入头文件的原因 - htons 程序在隐式声明中可以正常工作。如果struct addrinfo 被定义,getaddrinfo 也可以工作。或者如果它不会被取消引用。
猜你喜欢
  • 2016-02-27
  • 2011-04-21
  • 2012-05-13
  • 1970-01-01
  • 2012-03-28
  • 2016-11-01
  • 1970-01-01
  • 2012-09-12
相关资源
最近更新 更多