Search code examples
cmacrosstandards

"C89/C99 say they're macros. Make them happy."?


I found this interesting code in /usr/include/stdio.h on various Linux systems I have access to.

167 /* Standard streams.  */
168 extern struct _IO_FILE *stdin;      /* Standard input stream.  */
169 extern struct _IO_FILE *stdout;     /* Standard output stream.  */
170 extern struct _IO_FILE *stderr;     /* Standard error output stream.  */
171 /* C89/C99 say they're macros.  Make them happy.  */
172 #define stdin stdin
173 #define stdout stdout
174 #define stderr stderr

Screenshot Question: What's the point in defining a macro that does essentially nothing?


Solution

  • The C11 defines stdin, stdout and stderr in 7.21.1p3:

    1. The macros [defined in <stdio.h>] are

      [...]

      • stderr
      • stdin
      • stdout

      which are expressions of type pointer to FILE that point to the FILE objects associated, respectively, with the standard error, input, and output streams.

      [...]

    Since the standard says these are macros, they must be macros. However the expressions must have some definition, and the standard allows them to also be used as variable names, but they don't have to be actual identifiers.

    Linux userland tries to mostly conform to the POSIX standard in addition to conforming to the C11 standard. In POSIX, the requirement is that these symbols are external identifiers. Since C11 requires that they be macros and POSIX requires that they're external identifiers, this is achieved easiest by defining a macro by the exact same name as the corresponding identifier.

    It is indeed debatable if the POSIX standard intends them to also be variables with external linkage, but it is of note that POSIX.1 2008 standard does state in its System Interfaces volume that

    The only sections relating to conformance are the SYNOPSIS, DESCRIPTION, RETURN VALUE, and ERRORS sections.

    And the SYNOPSIS section for these does say that:

    SYNOPSIS

    #include <stdio.h>
    
    extern FILE *stderr, *stdin, *stdout;