Подтвердить что ты не робот

Препроцессор C: как создать символьный литерал?

Просто из любопытства, я хотел бы знать, можно ли определить макрос, который может превратить свой аргумент в литерал символа:

 switch(getchar()) {
   case MYMACRO(A): printf("Received A\n"); break;
   case MYMACRO(a): printf("Received a\n"); break;
   case MYMACRO(!): printf("Received an exclamation mark\n"); break;
   default: printf("Neither a nor A nor !\n"); break;
 }

Два возможных решения с головы:

Перечисление всех символов

#define LITERAL_a 'a'
#define LITERAL_b 'b'
...
#define MYMACRO(x) LITERAL_ ## x

Он не работает с MYMACRO(!), потому что ! не является допустимым компонентом идентификатора C.

Преобразование параметра в строковый литерал

#define MYMACRO(x) #x [0]

Он включает разыменование указателя и недействителен в таких местах, как метка case.

Я не прошу об "улучшении" вышеупомянутого оператора switch. Это просто игрушечный пример. Повторение. Это просто игрушечный пример.

4b9b3361

Ответ 1

Здесь мое возможное решение:

#define EVAL(...) __VA_ARGS__
#define Q() '
#define MYMACRO(...) Q()EVAL(__VA_ARGS__)Q()

(Макросы Variadic используются для поддержки MYMACRO(,), потому что он будет анализироваться как два пустых аргумента.)

Я не уверен, соответствует ли этот код стандартно-совместимому из-за непревзойденного '. Тем не менее, я думаю, что этот код работает на большинстве компиляторов C99. Однако этот код не работает для следующих символов:

  • (, который должен соответствовать )
  • ) используется для определения начала и конца списка аргументов
  • ' и ", используемые для строковых литералов и символьных констант
  • \, которому требуется экранировать
  • Простые символы, потому что они не являются маркерами

Я уверен, что нет решения, которое работает для (, ), ' или ", потому что, если это было разрешено, компилятору пришлось бы изменить способ анализа аргументов макросов.

Ответ 2

Хотя я не мог получить user4098326 ответ на компиляцию, я получил решение ниже для компиляции и работы, как ожидалось (в Code Composer Studio). Ключ должен был использовать оператор конкатенации символов. Обратите внимание, однако, что в соответствии со стандартом это не должно работать. Единая кавычка (') не является допустимым токеном, а не одной кавычкой, за которой следует один символ (' a). Таким образом, они не должны быть входом или выходом оператора конкатенации. Таким образом, я бы не рекомендовал использовать это решение.

#define CONCAT_H(x,y,z) x##y##z
#define SINGLEQUOTE '
#define CONCAT(x,y,z) CONCAT_H(x,y,z)
#define CHARIFY(x) CONCAT(SINGLEQUOTE , x , SINGLEQUOTE )

#define DO_CASE(...) case CHARIFY(__VA_ARGS__): printf("Got a " #__VA_ARGS__ "\n"); break

Тогда:

switch(getchar()) {
   DO_CASE(A);
   DO_CASE(a);
   DO_CASE(!);
   default: printf("Neither a nor A nor !\n"); break;
 }