为什么仅在定义__USE_XOPEN2K时才定义struct addrinfo?

Aug*_*ack 5 c gcc clang

我正在阅读getaddrinfo的手册页并尝试遵循示例代码,但它不能编译:

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

void f() {
    struct addrinfo t;
}
Run Code Online (Sandbox Code Playgroud)

两个都有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.
Run Code Online (Sandbox Code Playgroud)

和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;
                     ^
Run Code Online (Sandbox Code Playgroud)

经过一番挖掘后,我发现glibc头文件有一个预处理器指令,可以"保护"(这是正确的术语吗?)struct来定义,所以我想知道:

  • 为什么glibc使用#ifdef __USE_XOPEN2K其他人不使用?什么用于?为什么它从__USE_POSIX改变了?
  • 为什么铛和gcc定义__USE_XOPEN2K-std=gnu89,-std=gnu90,-std=gnu99但不与-ansi,-std=c89,-std=c90,-std=c99-std=c11
  • 我应该使用什么来获取错误?使用-std=gnuXX还是使用#define __USE_XOPEN2K

Aug*_*ack 9

简短的回答,如果你使用不属于标准C的API的glibc(任何与UNIX相关的东西),只需使用-std=gnuXX- 这将启用glibc中一些功能.文档


答案很长:

这是一个复杂的问题,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标准的范围非常有限,它提供了语法,语义和一些库头和函数.规范(c99c11)包含一些编译器应该公开的预定义宏,这些宏用于表示符合标准,因此程序可以使用旧规范没有的新功能,但是没有宏源代码可用于删除功能.

除了C编程语言规范之外,还有几个UNIX规范.试图制作一个长篇故事和错综复杂的历史,忽略商标和法律问题的问题:

最初UNIX没有规范,它的来源被非法复制和修改,结果是一长串 UNIX变体,其中一些发明了不兼容或冲突的API,如BSD的tty socket和SVR3 termio.一段时间后,工作组成立以标准化操作系统:

  • 1983Uniforum也知道/ usr/group创建了第一个名为核心UNIX系统的标准化
  • 1985年 AT&T拥有System V接口定义SVID
  • 1984 The Open Group也知道X/Open创建了X/Open可移植性指南XPG,
  • 1985IEEE 1003小组成立,他们创建了POSIX标准

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

  • 1983年 Uniforum创建了核心UNIX系统UDS 83 [Uniforum 1983草案标准]
  • 1985年 SVID取代了UDS 83
  • 1985年 XPG1,带有SVR24.2BSD的 API (POSIX plus套接字)
  • 1987,1990,1992 XPG2,XPG3XPG4
  • 1988至1995年构成该第一文件POSIX标准(1003.1,1003.2*,和1003.4)
  • 1997年 SUSv2
  • 2004 POSIX:2004SUSv3,2001版本更新[IEEE Std 1003.1-2004]
  • 2008 POSIX:2008 [IEEE Std 1003.1-2008]

首字母缩略词是:

  • SUS指的是Single UNIX Specification
  • XPG指的是X/Open Portability Guides
  • POSIX指的是便携式操作系统接口

好吧,现在GCC和glibc需要编译和链接任何用这些标准开发的C程序,glibc文档说:

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

海湾合作委员会关于语言方言的文件陈述如下:

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

还有关于标准库的文档:

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

有用的链接:

  • 为了让 VS Code Intellisense 在 GNU 标准下接受此代码,请运行命令 C/C++:编辑配置 (UI) 并从 C 标准选项中选择 gnu17 标准。 (4认同)