Реализуя свой собственный компилятор C11, я пытаюсь понять, как именно обрабатывать ключевое слово / оператор _Pragma
. C11 §6.10.9 описывает _Pragma
как оператор, поэтому кажется возможным переопределить его с помощью макросов, то есть #define _Pragma(x) SOME_OTHER_MACRO(x)
. Кроме того, инструкция #undef _Pragma
не должна иметь никакого эффекта (при условии, что не было ранее #define
из _Pragma
). Это похоже на то, как могут быть #define
d ключевые слова, например, старый VC ++ взлом #define for if (0) ; else for
. Однако, поскольку оператор _Pragma
оценивается во время фазы преобразования 3, той же фазы, что и выполнение директив препроцессора, неясно, является ли это исключением; в стандарте не упоминается, может ли его неопределенное поведение использовать _Pragma
в качестве имени макроса.
Я провел некоторое тестирование с GCC, используя следующий код:
#define PRAGMA _Pragma
PRAGMA("message \"hi\"")
_Pragma ("message \"sup\"")
#undef PRAGMA
#undef _Pragma
//#define _Pragma(x)
_Pragma("message \"hello\"")
Компиляция с gcc -std=c11 -pedantic -Wall -Wextra -c
выходами:
tmp.c:2:1: note: #pragma message: hi
PRAGMA("message \"hi\"")
^
tmp.c:4:1: note: #pragma message: sup
_Pragma ("message \"sup\"")
^
tmp.c:8:8: warning: undefining "_Pragma" [enabled by default]
#undef _Pragma
^
tmp.c:10:9: error: expected declaration specifiers or ‘...’ before string constant
_Pragma("message \"hello\"")
^
Если я добавлю строку #undef _Alignof
, GCC на это не пожалуется.
Это говорит о том, что GCC реализует _Pragma
через макрос (через предупреждающее сообщение), и что его удаление приводит к ошибке компиляции. Если я раскомментирую #define _Pragma(x)
, ошибка исчезнет (исчезнет строковый литерал).
Итак, мои вопросы:
- Разрешено ли реализациям определять
_Pragma
только как макрос, а не реализовывать его как оператор? - Если нет, то ошибается ли GCC в этом?
- если
_Pragma
должен быть оператором, является ли неопределенное поведение определение_Pragma
как макроса? - Есть ли какой-либо порядок между оценкой
_Pragma
и другими директивами препроцессора? Или у них одинаковый «приоритет» (т.е. они оцениваются по порядку)?
Опять же, при просмотре стандарта C11 ничего не упоминается о _Pragma
, кроме этого оператора, который можно использовать для #pragma
директив.
void main(void)
обсуждения), однако ваше исследование очевидно, и ваши вопросы хорошо представлены. Должен привести к интересным откликам. (+1) - person ryyker   schedule 23.07.2014#ifndef _Pragma <newline>#undef _Pragma<newline>#endif
не будет вызывать UB - person Drew McGowen   schedule 23.07.2014