Включение stdint.h в заголовочный файл прерывает компиляцию с помощью 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
Я компилирую и связываю со следующими опциями:
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>
в моих настройках ч компиляция файла с clock_gettime()
?
Я думаю, что stdint
переопределяет POSIX
определить, но это не имеет смысла для меня, так как -include
Директива работает так, как будто включение было сделано в первой строке источника.
Вот пример (в свете ответа Джона Боллинджера я начинаю понимать, что происходит не так, но я все равно решил написать это).
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 ответ
Как указывало rici, POSIX требует, чтобы (пере) определения любого из макросов тестирования возможностей, которые он определяет, предшествовали включению любого из указанных заголовков, в том числе другими заголовочными файлами, иначе поведение не определено. _POSIX_C_SOURCE
макрос является таким макросом для проверки возможностей, и stdint.h
а также time.h
оба такие заголовки.
В вашем конкретном случае библиотека GNU C stdint.h
заголовок и многие другие полагаются на общий внутренний заголовок (features.h
) который проверяет, какие функции явно включены, и устанавливает для всех макросов функции постоянные значения (насколько это возможно). Это может как проверить значение _POSIX_C_SOURCE
макрос и установить его, если он еще не был установлен. Он использует стандартный защитный макрос, чтобы избежать многократной обработки. Поэтому, если макрос объекта будет переопределен позже, вы рискуете получить противоречивые определения функций.
Я не проследил точную цепочку определений и переопределений, которая вызывает clock_gettime()
чтобы не быть объявленным в вашем конкретном случае (и действительно, вы не предоставили мне достаточно информации для этого), но если вы собираетесь определять функциональные макросы, то вы должны убедиться, что все заголовки видят эти определения. Они должны появиться в вашем исходном файле перед любым #include
директивами, и вам следует избегать иным образом предварительной обработки любых системных заголовков перед этими определениями (например, с помощью директивы в файле, названном в вашем -include
опция).
Также обратите внимание, что хотя мы обсуждаем детали реализации, нет никаких оснований полагать, что реализация GNU необычна в этом отношении. Другие будут реализованы несколько иначе, но всегда разумно убедиться, что все заголовки видят согласованный набор определений для любых макросов, которые их затрагивают. Даже для макросов, которые не указаны в POSIX.