_Прагма и макрозамена

При реализации моего собственного компилятора C11 я пытаюсь выяснить, как именно обрабатывать ключевое слово/оператор _Pragma. C11 §6.10.9 описывает _Pragma как оператор, поэтому представляется возможным переопределить его с помощью макросов, т.е. #define _Pragma(x) SOME_OTHER_MACRO(x). Кроме того, утверждение #undef _Pragma не должно иметь эффекта (если не считать предшествующего #define of _Pragma). Это похоже на то, как ключевые слова могут быть #define d, например старый VС++ hack #define for if (0) ; else for. Однако, поскольку оператор _Pragma оценивается во время фазы 3 перевода, на той же фазе, что и при выполнении директив препроцессора, неясно, является ли это исключением; в стандарте не упоминается, использовать ли его undefined поведение _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 должен быть оператором, является ли поведение undefined определять _Pragma как макрос?
  • Есть ли порядок между оценкой _Pragma и другими директивами препроцессора? Или они имеют одинаковый "приоритет" (т.е. Оцениваются в порядке)?

Опять же, просмотр стандарта C11 не упоминает ничего о _Pragma, кроме него, оператора, который может использоваться для директив #pragma.

Ответ 1

Нет необходимости в специальном правиле, которое запрещало бы _Pragma быть именем макроса. Имея ведущую подчеркивание и заглавную букву, это в числе зарезервированных идентификаторов, которые вы не должны использовать, так или иначе. Использование зарезервированных идентификаторов приводит к undefined поведению вашей программы, компилятор может что-то сделать.

Реализация может реализовать его как макрос, но это должно быть прозрачным для вас, если вы используете его правильно, так как пока вы не обходитесь с ним. Единственная важная вещь, которую должна гарантировать реализация, заключается в том, что "destringization" и "tokeninzation" аргумента _Pragma выполняется так, как если бы в фазе 3 (что сложно, если это "только" макрос), и что результирующая директива #pragma обрабатывается в фазе 4.