在头文件中包含stdint.h会破坏与clock_gettime()的编译

时间:2015-02-17 15:24:06

标签: c gcc posix stdint

我的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

我使用以下选项进行编译和链接:

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>,然后再次编译。

为什么在我的设置中包含<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

1 个答案:

答案 0 :(得分:1)

正如rici指出的那样,POSIX要求(重新)定义它指定的任何特征测试宏,包括它指定的任何头,包括其他头文件,否则行为是未定义的。 _POSIX_C_SOURCE宏是一个功能测试宏,stdint.htime.h都是这样的标题。

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

我没有追溯导致clock_gettime()未能在您的特定情况下声明的确切定义和重新定义链(事实上,您没有提供足够的信息供我这样做),但如果如果要定义功能宏,则应确保所有标头都能看到这些定义。它们应该在任何#include指令之前出现在源文件中,并且应该避免在这些定义之前导致任何系统头文件被预处理(例如,通过-include选项中指定的文件中的指令)。

另请注意,虽然我们正在讨论实现细节,但没有理由认为GNU的实现在这方面是不寻常的。其他人的实现方式有所不同,但始终明智地确保所有标头都能看到影响它们的任何宏的一致定义集。即使是没有POSIX指定的宏。