Конкатенация строк с использованием препроцессора - PullRequest
18 голосов
/ 24 февраля 2011

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

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

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

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

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

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

Ответы [ 4 ]

40 голосов
/ 24 февраля 2011

Объединение соседних строковых литералов не является особенностью препроцессора, это особенность основных языков (как C, так и C ++). Вы могли бы написать:

printf("Hello "
       " world\n");
19 голосов
/ 24 февраля 2011

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

#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);
12 голосов
/ 24 февраля 2011

С gcc онлайн-документы :

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

Рассмотрим программу на 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),
   ...
 };
6 голосов
/ 15 декабря 2014

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

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

Литеральные токены смежных строк объединяются.

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

6 Смежные обычные строковые литеральные токены объединяются.Смежные широкие строковые литеральные токены объединяются.

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

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

>> ./a.out
>> string one

Часть предварительной обработкивопрос заключается просто в использовании директивы предварительной обработки #define, которая выполняет подстановку из идентификатора (H) в строку ("Hello ").

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...