libc 包括不遵守源类型参数更改的守卫

libc include guards not respecting source type parameter changes

问题

如果我包含 time.h,将 "source type parameter" 和 re-include 更改为 header,它不应该添加那些新定义吗?我知道这是由于包括警卫而发生的。我的问题是:这是 libc 中的错误吗?它不应该能够处理这个吗?

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

static struct timespec t;

错误信息:

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

背景

我在使用 -std=c99 编译时发现了构建 Python 扩展的行为。如果我在包含 Python.h 之前包含标准库,我会由于缺少 POSIX 功能的定义而出现编译错误。如果我将 Python.h 包含在其他所有内容之前,一切都很好。当然用 -std=gnu99 编译也可以。但我想深入了解错误发生的原因并将其提炼为上面的代码示例。

这引出了另一个问题。如果上述行为不是错误,那么在 header 中设置 _XOPEN_SOURCE 和类似的源类型参数是否被认为是不好的做法? Python 是否应该在他们的 header 中删除该参数的设置,而是要求用户在编译期间定义它,或者使用 std=gnu99?

你所说的 "source type parameters" 被称为功能测试宏,在包含 any 标准 header 之前特别需要定义它们,如果它们完全被定义了。

这是在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.

Linux man page for feature-test-macros也明确规定了标准及其扩展的要求:

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

您不能重新定义和重新包含 headers 来改变事物,事实上在 headers 之间定义或 undefining/redefining 它们(甚至不同,看似无关的 headers ) 可能会彻底破坏。