libc include guards not respecting source type parameter changes

Viewed 76

Question

If I include time.h, change a "source type parameter" and re-include that header, shouldn't it add in those new definitions? I understand that this is happening due to include guards. My question is: is this a bug in libc? Shouldn't it be able to handle this?

#include <time.h>
#define _XOPEN_SOURCE 600
#include <time.h>

static struct timespec t;

Error message:

example.c:5:24: error: storage size of ‘t’ isn’t known
    5 | static struct timespec t;
      |                        ^

Background

I discovered this behavior building a Python extension while compiling with -std=c99. If I included standard libraries before I included Python.h I would get compilation errors due to missing definitions of POSIX functionality. If I moved the Python.h include before everything else, all was fine. Of course compiling with -std=gnu99 works as well. But I wanted to get to the bottom of why the error was occurring and distilled it down to the above code sample.

Which begs another question. If the above behavior isn't a bug, is setting _XOPEN_SOURCE and similar source type parameters in a header considered bad practice? Should Python remove the setting of that parameter in their headers and instead require users to define it during compilation, or use std=gnu99?

1 Answers

What you're calling "source type parameters" are called feature test macros, and they are specifically required to be defined before inclusion of any standard header if they are defined at all.

This is specified in XSH 2.2.1 POSIX.1 Symbols:

A POSIX-conforming application shall ensure that the feature test macro _POSIX_C_SOURCE is defined before inclusion of any header.

...

An XSI-conforming application shall ensure that the feature test macro _XOPEN_SOURCE is defined with the value 700 before inclusion of any header.

The Linux man page for feature-test-macros also clearly states this requirement for the standard ones and its extensions:

NOTE: In order to be effective, a feature test macro must be defined before including any header files

You cannot redefine and reinclude headers to change things, and in fact defining or undefining/redefining them between headers (even different, seemingly unrelated headers) may completely break things.

Related