Конкатенация строк с использованием препроцессора

Можно ли объединить строки во время предварительной обработки?

Я нашел этот пример

#define H "Hello "
#define W "World!"
#define HW H W

printf(HW); // Prints "Hello World!"

Однако это не работает для меня - выводит "Привет", когда я использую gcc -std=c99

UPD Этот пример выглядит как работающий сейчас. Однако, это обычная функция препроцессора c?

Ответы

Ответ 1

Конкатенация смежных строк litterals не является особенностью препроцессора, это особенность основных языков (как C, так и С++). Вы можете написать:

printf("Hello "
       " world\n");

Ответ 2

Вы можете объединить токены в препроцессоре, но будьте осторожны, потому что это сложно. Ключ - это оператор ##. Если бы вы выбрали это в верхней части кода:

#define myexample(x,y,z) int example_##x##_##y##_##z## = x##y##z 

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

myexample(1,2,3);

и он буквально превратится в

int example_1_2_3 = 123;

Это позволяет вам обладать гибкостью при кодировании, если вы используете его правильно, но это не совсем верно, как вы пытаетесь его использовать. С небольшим массажем вы можете заставить его работать, хотя.

Одним из возможных решений для вашего примера может быть:

#define H "Hello "
#define W "World!"
#define concat_and_print(a, b) cout << a << b << endl

а затем сделайте что-то вроде

concat_and_print(H,W);

Ответ 3

Из gcc online docs:

Оператор предварительной обработки '##' выполняет вставку маркера. Когда макрос расширяется, два токена по обе стороны каждого оператора "##" объединены в один токен, который затем заменяет "##" и два оригинальных токена в расширении макроса.

Рассмотрим программу на языке C, которая интерпретирует именованные команды. Вероятно, должна быть таблица команд, возможно, массив структур, объявленный следующим образом:

 struct command
 {
   char *name;
   void (*function) (void);
 };

 struct command commands[] =
 {
   { "quit", quit_command },
   { "help", help_command },
   ...
 };

Было бы проще не указывать имя каждой команды дважды, один раз в строковой константе и один раз в имени функции. Макрос, который принимает имя команды в качестве аргумента, может сделать это ненужным. Строковая константа может быть создана с помощью строкования и имя функции, объединяя аргумент с помощью _command. Вот как это делается:

 #define COMMAND(NAME)  { #NAME, NAME ## _command }

 struct command commands[] =
 {
   COMMAND (quit),
   COMMAND (help),
   ...
 };

Ответ 4

Я просто подумал, что добавлю ответ, который ссылается на источник, почему это работает.

Стандарт C99 §5.1.1.2 определяет фазы перевода кода C. В подразделе 6 говорится:

  1.   
  2. Связанные токены строковых литералов конкатенированы.  

Аналогично, в стандартах С++ (ISO 14882) в § 2.1 определяются этапы перевода. Здесь в подразделе 6 говорится:

6 Смежные обычные строковые литералы связаны друг с другом. Смежные широкоформатные литеральные жетоны конкатенированы.

Вот почему вы можете конкатенировать строки просто, смещая их друг с другом:

printf("string"" one\n");

>> ./a.out
>> string one

Предпроцессорная часть вопроса - это просто использование директивы #define preprocessing, которая выполняет подстановку из идентификатора (H) в строку ("Hello ").