【问题标题】:Why is struct addrinfo defined only if __USE_XOPEN2K is defined?为什么 struct addrinfo 仅在定义了 __USE_XOPEN2K 时才定义?
【发布时间】:2015-10-12 08:09:15
【问题描述】:

我正在阅读 getaddrinfo 的手册页并尝试按照示例代码进行操作,但无法编译:

// test.c
#include <netdb.h>

void f() {
    struct addrinfo t;
}

都带有clang:

$ clang -std=c11 test.c
test.c:10:21: error: variable has incomplete type 'struct addrinfo'
    struct addrinfo t;
                    ^
test.c:10:12: note: forward declaration of 'struct addrinfo'
    struct addrinfo t;
           ^
1 error generated.

和 gcc:

$ gcc -std=c11 test.c
test.c: In function ‘f’:
test.c:10:21: error: storage size of ‘t’ isn’t known
     struct addrinfo t;
                     ^

经过一番挖掘,我发现glibc headers 有一个预处理器指令“保护”(这是正确的术语吗?)struct 被定义,所以我想知道:

  • 为什么glibc 使用#ifdef __USE_XOPEN2Kothers don't?有什么用?为什么它从 __USE_POSIX 变成了?
  • 为什么clang和gcc用-std=gnu89-std=gnu90-std=gnu99定义__USE_XOPEN2K而不用-ansi-std=c89-std=c90-std=c99-std=c11?>
  • 我应该使用什么来避免出现错误?使用-std=gnuXX 还是使用#define __USE_XOPEN2K

【问题讨论】:

  • 我也想知道这一点,在我的情况下,因为它阻止了 pthreads 中的障碍被定义。
  • __USE_XOPEN2K__USE_POSIX 等名称由实现处理,您不应尝试自己直接设置它们。您应该设置_XOPEN_SOURCE_POSIX_C_SOURCE — 具有已定义的效果,包括公开诸如struct addrinfo 之类的声明。使用 -std=gnu11 或类似的东西可以启用所有这些和(可能)额外的 GNU 扩展。在某些方面,它更简单。

标签: c gcc clang


【解决方案1】:

简短的回答,如果您将 glibc 与不属于标准 C(任何与 UNIX 相关)的 API 一起使用,只需使用 -std=gnuXX — 这将启用 couple of features in the glibcdocs


长答案:

这是一件复杂的事情,C 编程语言和 Unix 操作系统都很老旧,而且有很多包袱;这是我试图理解这一切的尝试。

有一种 C 编程语言。该语言出现于 1972 年,但直到 1989 年第一个 ANSI C 被批准时才标准化。目前C编程语言有这些规范:

  • 1989 称为 ANSI CC89 [X3.159-1989]。
  • 1990 称为 ISO CC90 [ISO/IEC 9899:1990]
  • 1995 称为 AMD1C94C95 [ISO/IEC 9899:1990/AMD 1:1995]
  • 1999 称为 C99 [ISO/IEC 9899:1999]
  • 2011 称为 C11C1X [ISO/IEC 9899:2011]

C 标准有一个真正的limited scope,它提供了语法、语义和some library headers and functions。规范(c99c11)包含一些编译器应该公开的预定义宏,这些宏用于指示符合标准,以便程序可以使用旧规范没有的新功能,但是有不是源代码可以用来删除功能的宏。

除了 C 编程语言规范之外,还有几个 UNIX specifications。试图缩短long story 和复杂的历史,忽略商标和法律术语的问题:

一开始 UNIX 没有规范,它的源代码被非法复制和修改,结果是 UNIX 变体的long list,其中一些发明了不兼容或冲突的 API,例如 BSD 的 tty 套接字和 SVR3 termio .一段时间后,为了标准化操作系统而成立了工作组:

  • 1983 Uniforum 也称为 /usr/group 创建了第一个名为 core UNIX System 的标准化
  • 1985 AT&TSystem V 接口定义SVID
  • 1984The Open Group 也被称为 X/Open 创建了 X/Open Portability Guide XPG,
  • 1985 IEEE 1003 组成立,他们创建了 POSIX 标准

这些小组的工作可以用这个不完整的时间表来描述:

  • 1983 Uniforum 创建了 core UNIX SystemUDS 83 [Uniforum 1983 Draft Standard]
  • 1985 SVID 取代 UDS 83
  • 1985 XPG1 使用来自 SVR24.2BSD 的 API(POSIX 加套接字)
  • 1987,1990,1992 XPG2XPG3XPG4
  • 1988 - 1995 组成 POSIX 标准的第一个文档(1003.1、1003.2* 和 1003.4)李>
  • 1997 SUSv2
  • 2004 POSIX:2004SUSv3,2001 版本的更新 [IEEE 标准 1003.1-2004]
  • 2008 POSIX:2008 [IEEE 标准 1003.1-2008]

缩写词是:

  • SUS 指的是单一 UNIX 规范
  • XPG 指的是X/Open Portability Guides
  • POSIX 指的是便携式操作系统接口

好的,所以现在 GCC 和 glibc 需要编译并链接到考虑到任何这些标准开发的任何 C 程序,glibc docs 说:

如果您使用“gcc -ansi”编译您的程序,则您只能获得 ISO C 库功能,除非您通过定义一个或多个功能宏来明确请求其他功能 [...]。您应该使用源代码文件顶部的“#define”预处理器指令来定义这些宏。这些指令必须位于系统头文件的任何#include 之前[...]。该系统的存在是为了让库符合多种标准。

GCC 关于language's dialects 的文档陈述如下:

-ansi 等同于-std=c90 [...]。这将关闭与 ISO C90 (编译 C 代码时)不兼容的 GCC 的某些功能,例如 asm 和 typeof 关键字,以及用于识别您的系统类型的预定义宏(例如 unix 和 vax)正在使用。 -std=‘c89’ 与 C 代码的 -ansi 相同。

还有关于standard libraries的文档:

如果您需要一个符合标准的库,那么您需要找到一个,因为 GCC 不提供。 GNU C 库(称为 glibc)为 GNU/Linux 和基于 HURD 的 GNU 系统提供 ISO C、POSIX、BSD、SystemV 和 X/Open 兼容性;

有用的链接:

【讨论】:

  • 这里有很多很好的信息。您没有提到您可以选择哪个版本的 POSIX 或 X/Open (SUS) 规范,例如,使用 #define _XOPEN_SOURCE 700(对于对应于 POSIX 2008 的 SUS)或 #define _POSIX_C_SOURCE 200809(对于 POSIX 2008)。一般来说,_XOPEN_SOURCE 700 大致相当于_POSIX_C_SOURCE 200809L_XOPEN_SOURCE 600 大致等同于 _POSIX_C_SOURCE 200112L;并且_XOPEN_SOURCE 500 大致等同于_POSIX_C_SOURCE 199506L
猜你喜欢
  • 1970-01-01
  • 2014-06-17
  • 1970-01-01
  • 1970-01-01
  • 2013-06-23
  • 2016-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多