在头文件中包含 stdint.h 中断了使用 clock_gettime() 的编译

Include of stdint.h in a header file breaks compiling with clock_gettime()

我的 C 文件使用 clock_gettime()。为此,它包含 <time.h> 并根据手册页将 _POSIX_C_SOURCE 定义为 (200112L)

SYNOPSIS
       #include <time.h>

       int clock_getres(clockid_t clk_id, struct timespec *res);

       int clock_gettime(clockid_t clk_id, struct timespec *tp);

       int clock_settime(clockid_t clk_id, const struct timespec *tp);

       Link with -lrt (only for glibc versions before 2.17).

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       clock_getres(), clock_gettime(), clock_settime():
              _POSIX_C_SOURCE >= 199309L

我编译并 link 使用以下选项:

CFLAGS = -g -Wall -Wextra -Werror -O3 -std=c99 -include $(PROJ_SETTINGS_INC) -lrt

,并且 PROJ_SETTINGS_INC 设置为包含设置的 h 文件。

到目前为止,没问题。

现在我修改我的设置文件并使用uint16_t,所以我在设置h文件中包含<stdint.h>

编译器现在抱怨 clock_gettime() 是隐式声明。

如果我改回我的设置文件以使用 int 而不是 uint16_t,并删除对 <stdint.h> 的包含,然后编译再次工作。

为什么在我的设置 h 文件中包含 <stdint.h> 会中断使用 clock_gettime() 的编译?

我最好的猜测是 stdint 重新定义了 POSIX 定义,但这对我来说没有意义,因为 -include 指令就像在来源的第一行。


这是一个例子(根据 John Bollinger 的回答,我开始明白出了什么问题,但我想我还是会写这个)。

bar.h:

#include <stdint.h>

struct s {
    uint16_t a;
};

foo.c

#define _POSIX_C_SOURCE (199309L)

#include <stdio.h>
#include <time.h>

int main(void)
{
    struct s s;
    struct timespec now;

    s.a = 42;
    clock_gettime(CLOCK_REALTIME, &now);

    printf("answer: %d, time: %lld\n", s.a, (long long) now.tv_sec);

    return 0;
}

构建:

gcc foo.c -include bar.h

奇怪的是,这给出了一个有用的警告。在我原来的应用程序中,我只得到隐式声明错误。

foo.c:1:0: warning: "_POSIX_C_SOURCE" redefined [enabled by default]
 #define _POSIX_C_SOURCE (199309L)
 ^
In file included from /usr/include/stdint.h:25:0,
                 from /usr/lib/gcc/x86_64-linux-gnu/4.8/include/stdint.h:9,
                 from ./bar.h:1,
                 from <command-line>:1:
/usr/include/features.h:230:0: note: this is the location of the previous definition
 # define _POSIX_C_SOURCE 200809L

正如 rici 指出的那样,POSIX 要求(重新)定义它指定的任何功能测试宏,然后再包含它指定的任何 header,包括其他 header 文件,否则行为未定义。 _POSIX_C_SOURCE宏就是这样一个feature-test宏,stdint.htime.h都是这样的header。

在您的特定情况下,GNU C 库的 stdint.h header 和许多其他库依赖于一个共同的内部 header (features.h) 检查哪些功能是明确的启用并将所有功能宏设置为一致的值(只要这是可能的)。它可能同时检查 _POSIX_C_SOURCE 宏的值,如果尚未设置则设置它。它使用标准的保护宏来避免被多次处理。因此,如果稍后重新定义特征宏,则可能存在特征定义不一致的风险。

我没有追查导致 clock_gettime() 在您的特定情况下无法声明的确切定义和重新定义链(事实上,您没有提供足够的信息让我这样做),但是如果你要定义功能宏,那么你应该确保 all headers 看到这些定义。它们应该出现在任何 #include 指令之前的源文件中,并且您应该避免以其他方式导致任何系统 header 在这些定义之前被预处理(例如,通过 [=18] 中命名的文件中的指令=] 选项).

还要注意,虽然我们正在讨论实现细节,但没有理由认为 GNU 的实现在这方面是不寻常的。其他人的实施方式会有所不同,但总是 明智的做法是确保所有 header 都能看到影响它们的任何宏的一致定义集。即使对于 POSIX.

未指定的宏