0

我的 C 文件使用clock_gettime(). 为此,它包括<time.h>并定义_POSIX_C_SOURCEto (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,因此我将其包含<stdint.h>在设置 h 文件中。

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

如果我将我的设置文件改回使用int而不是uint16_t,并将包含删除为<stdint.h>,则再次编译。

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

我最好的猜测是stdint重新定义了POSIX定义,但这对我来说没有意义,因为该-include指令的工作方式就像在源代码的第一行中完成了包含一样。


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

酒吧.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
4

1 回答 1

1

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

在您的特定情况下,GNU C 库的stdint.h标头和许多其他标头依赖于一个通用的内部标头 ( features.h),该标头检查哪些功能已显式启用并将所有功能宏设置为一致的值(尽可能)。它既可以检查_POSIX_C_SOURCE宏的值,也可以设置它(如果尚未设置)。它使用标准的保护宏来避免被多次处理。因此,如果稍后重新定义功能宏,那么您将面临功能定义不一致的风险。

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

还要注意,尽管我们正在讨论实现细节,但没有理由认为 GNU 的实现在这方面是不寻常的。其他的实现方式会有所不同,但确保所有标头看到影响它们的任何宏的一致定义集总是明智的。即使对于 POSIX 未指定的宏也是如此。

于 2015-02-17T16:36:23.763 回答