2015-02-17 4 views
0

В моем файле C используется clock_gettime(). Для этой работы он включает в себя <time.h> и определяет _POSIX_C_SOURCE к (200112L), согласно странице человека: Включить stdint.h в файл заголовка разбивает компиляцию с помощью clock_gettime()

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 директива работает, если включать это было сделано в первой строке источника.


Вот пример (в свете ответа Джона Боллинджера, я начинаю понимать, что происходит не так, но я думал, что я пишу это в любом случае).

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 
+2

Может быть необходимо поставить #define перед ** all ** # include. – user4098326

+0

Глядя на выход препроцессора поможет - http://stackoverflow.com/questions/19443520/how-to-output-the-intermediate-file-after-gcc-has-included-all-header-files-for/19443632 # 19443632 – amdn

+0

Можете ли вы показать содержимое файла '$ (PROJ_SETTINGS_INC)'? – ouah

ответ

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.

+1

Это не просто целесообразно. Это обязательно. Определение макроса теста функции Posix после #include заголовка, указанного в Posix (который включает стандартные заголовки библиотеки), является неопределенным поведением. См. Третий абзац http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_02 – rici

+0

Спасибо, @rici. Я обновил свой ответ, чтобы обратить особое внимание на спецификации POSIX и поместить остальную часть ответа в этом контексте. –

+0

Да, правильно! Это не похоже на то, что вам нужна дополнительная информация, чтобы точно определить проблему, но я все равно редактировал свой вопрос с кодом. В качестве продолжения я не уверен, что лучший способ использовать 'clock_gettime'. Я все еще хочу включить файл из команды сборки (чтобы иметь возможность строить с разными файлами с помощью 'PROJ_SETTINGS_INC = my_file.h make'), но если этот файл нуждается в' stdint.h', у меня проблемы. Каково общее решение этого, это должно происходить часто? Должен ли я определять '_POSIX_C_SOURCE' в' CFLAGS' с '-D'? – Gauthier

 Смежные вопросы

  • Нет связанных вопросов^_^