在头文件中包含 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.h
和time.h
都是这样的header。
在您的特定情况下,GNU C 库的 stdint.h
header 和许多其他库依赖于一个共同的内部 header (features.h
) 检查哪些功能是明确的启用并将所有功能宏设置为一致的值(只要这是可能的)。它可能同时检查 _POSIX_C_SOURCE
宏的值,如果尚未设置则设置它。它使用标准的保护宏来避免被多次处理。因此,如果稍后重新定义特征宏,则可能存在特征定义不一致的风险。
我没有追查导致 clock_gettime()
在您的特定情况下无法声明的确切定义和重新定义链(事实上,您没有提供足够的信息让我这样做),但是如果你要定义功能宏,那么你应该确保 all headers 看到这些定义。它们应该出现在任何 #include
指令之前的源文件中,并且您应该避免以其他方式导致任何系统 header 在这些定义之前被预处理(例如,通过 [=18] 中命名的文件中的指令=] 选项).
还要注意,虽然我们正在讨论实现细节,但没有理由认为 GNU 的实现在这方面是不寻常的。其他人的实施方式会有所不同,但总是 明智的做法是确保所有 header 都能看到影响它们的任何宏的一致定义集。即使对于 POSIX.
未指定的宏
我的 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.h
和time.h
都是这样的header。
在您的特定情况下,GNU C 库的 stdint.h
header 和许多其他库依赖于一个共同的内部 header (features.h
) 检查哪些功能是明确的启用并将所有功能宏设置为一致的值(只要这是可能的)。它可能同时检查 _POSIX_C_SOURCE
宏的值,如果尚未设置则设置它。它使用标准的保护宏来避免被多次处理。因此,如果稍后重新定义特征宏,则可能存在特征定义不一致的风险。
我没有追查导致 clock_gettime()
在您的特定情况下无法声明的确切定义和重新定义链(事实上,您没有提供足够的信息让我这样做),但是如果你要定义功能宏,那么你应该确保 all headers 看到这些定义。它们应该出现在任何 #include
指令之前的源文件中,并且您应该避免以其他方式导致任何系统 header 在这些定义之前被预处理(例如,通过 [=18] 中命名的文件中的指令=] 选项).
还要注意,虽然我们正在讨论实现细节,但没有理由认为 GNU 的实现在这方面是不寻常的。其他人的实施方式会有所不同,但总是 明智的做法是确保所有 header 都能看到影响它们的任何宏的一致定义集。即使对于 POSIX.
未指定的宏