Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is struct addrinfo defined only if __USE_XOPEN2K is defined?

Tags:

c

gcc

clang

I'm reading the man page for getaddrinfo and trying to follow the example code, but it doesn't compile:

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

void f() {
    struct addrinfo t;
}

Both with 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.

and 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;
                     ^

After some digging I found that the glibc headers have a preprocessor directive that "protects" (is this the right term?) the struct from being defined, so I'm wondering:

  • Why does glibc uses #ifdef __USE_XOPEN2K and others don't? what is used for? why did it change from __USE_POSIX?
  • Why clang and gcc define __USE_XOPEN2K with -std=gnu89, -std=gnu90, -std=gnu99 but not with -ansi, -std=c89, -std=c90, -std=c99 and -std=c11?
  • What should I use to not get the error? Use -std=gnuXX or use #define __USE_XOPEN2K?
like image 953
Augusto Hack Avatar asked Oct 12 '15 08:10

Augusto Hack


1 Answers

Short answer, if you are using glibc with APIs that are not part of the standard C (anything UNIX related) just use the -std=gnuXX — this will enable a couple of features in the glibc. docs


Long answer:

This is a complex matter, the C programming language and the Unix OSs are old and have a lot of baggage; this is my try at understanding all of this.

There is a C programming language. The language appeared in the year 1972 but it was not standardized until 1989, when the first ANSI C was ratified. Currently there are these specifications of the C programming language:

  • 1989 Known as the ANSI C or C89 [X3.159-1989].
  • 1990 Known as the ISO C or C90 [ISO/IEC 9899:1990]
  • 1995 Known as the AMD1 or C94 or C95 [ISO/IEC 9899:1990/AMD 1:1995]
  • 1999 Known as the C99 [ISO/IEC 9899:1999]
  • 2011 Known as the C11 or C1X [ISO/IEC 9899:2011]

The C standard has a really limited scope, it provides the syntax, semantics, and some library headers and functions. The specifications (c99 and c11) contained some predefined macros that the compiler should expose, these macros are used to indicate conformance to the standard, so that the program can use new features that older specifications didn't have, but there is no macro that the source code could use to remove features.

Besides the C programming language specification there are a couple of UNIX specifications. Trying to make a long story and convoluted history short, ignoring problems with the trademark and legalese:

At the beginning UNIX did not have a specification and it's source was sort of illegally copied and modified, the result is a long list of UNIX variants, some of which invented incompatible or conflicting APIs, like BSD's tty socket and SVR3 termio. After some time working groups were formed to standardize the OS:

  • 1983 The Uniforum also know as /usr/group created the first standardization named as core UNIX System
  • 1985 AT&T had the System V Interface Definition or SVID
  • 1984 The The Open Group also know as X/Open created the X/Open Portability Guide or XPG,
  • 1985 The IEEE 1003 group was created, they created the POSIX standard

The work of these groups can be describe with this incomplete timeline:

  • 1983 Uniforum created core UNIX System or UDS 83 [Uniforum 1983 Draft Standard]
  • 1985 SVID superseded UDS 83
  • 1985 XPG1 with APIs from SVR2 and 4.2BSD (POSIX plus sockets)
  • 1987,1990,1992 XPG2, XPG3, and XPG4
  • 1988 - 1995 The first documents that compose the POSIX standard (1003.1, 1003.2*, and 1003.4)
  • 1997 SUSv2
  • 2004 POSIX:2004 or SUSv3, an updated of the 2001 version [IEEE Std 1003.1-2004]
  • 2008 POSIX:2008 [IEEE Std 1003.1-2008]

The acronyms are:

  • SUS refers to Single UNIX Specification
  • XPG refers to X/Open Portability Guides
  • POSIX refers to Portable Operating System Interface

Okay, so now GCC and the glibc need to compile and link against any C program developed with any of these standards in mind, the glibc docs says:

If you compile your programs using ‘gcc -ansi’, you get only the ISO C library features, unless you explicitly request additional features by defining one or more of the feature macros [...]. You should define these macros by using ‘#define’ preprocessor directives at the top of your source code files. These directives must come before any #include of a system header file [...]. This system exists to allow the library to conform to multiple standards.

GCC's docs about language's dialects states the following:

-ansi is equivalent to -std=c90 [...]. This turns off certain features of GCC that are incompatible with ISO C90 (when compiling C code), such as the asm and typeof keywords, and predefined macros such as unix and vax that identify the type of system you are using. -std=‘c89’ is the same as -ansi for C code.

Also the docs about standard libraries:

If you need a standard-compliant library, then you need to find one, as GCC does not provide one. The GNU C library (called glibc) provides ISO C, POSIX, BSD, SystemV and X/Open compatibility for GNU/Linux and HURD-based GNU systems;

Useful links:

  • GCC Standards
  • iso-9899 wiki
  • SO: Where can I find the C89/C90 standards in PDF format?
like image 62
Augusto Hack Avatar answered Sep 27 '22 23:09

Augusto Hack