Как создать новую строку в макросе cpp? - PullRequest
36 голосов
/ 19 сентября 2008

Как мне написать макрос cpp, который расширяется, чтобы включать переводы строки?

Ответы [ 7 ]

16 голосов
/ 03 апреля 2016

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

Допустим, у нас есть макрос C / C ++, который занимает несколько строк, например в файле с именем MyMacro.hpp

// Content of MyMacro.hpp

#include "MultilineMacroDebugging.hpp"

#define PRINT_VARIABLE(S) \
__NL__  std::cout << #S << ": " << S << std::endl; \
__NL__  /* more lines if necessary */ \
__NL__  /* even more lines */

В каждый файл, где я определил такой макрос, я включаю другой файл MultilineMacroDebugging.hpp , который содержит следующее:

// Content of MultilineMacroDebugging.hpp

#ifndef HAVE_MULTILINE_DEBUGGING
#define __NL__
#endif

Это определяет пустой макрос __NL__, из-за которого определения __NL__ исчезают во время предварительной обработки. Макрос затем может быть использован где-нибудь, например, в файле с именем MyImplementation.cpp .

// Content of MyImplementation.cpp

// Uncomment the following line to enable macro debugging
//#define HAVE_MULTILINE_DEBUGGING

#include "MyMacro.hpp"

int a = 10;
PRINT_VARIABLE(a)

Если мне нужно отладить макрос PRINT_VARIABLE, я просто раскомментирую строку, определяющую макрос HAVE_MULTILINE_DEBUGGING в MyImplementation.cpp . Результирующий код, конечно, не компилируется, так как результаты макроса __NL__ не определены, что приводит к тому, что он остается в скомпилированном коде, но, однако, его можно предварительно обработать.

Важным шагом сейчас является замена строки __NL__ в выводе препроцессора символами новой строки с использованием вашего любимого текстового редактора, и, вуаля, вы получите читаемое представление результата замененного макроса после предварительной обработки, которое точно соответствует тому, что компилятор будет видеть, за исключением искусственно введенных символов новой строки.

8 голосов
/ 19 сентября 2008

Компиляторы C & C ++ игнорируют пробельные символы без кавычек (за исключением проблемы с шаблоном>>), поэтому получение макроса для вывода новых строк не имеет смысла. Макрос может занимать несколько строк, заканчивая каждую строку макроса обратной косой чертой, но это не выводит символы новой строки.

7 голосов
/ 19 сентября 2008

Это невозможно. Это было бы уместно, только если вы просматривали список файлов или вывод препроцессора.

Обычный способ написания макросов, чтобы их было легче читать, - использовать символ \ для продолжения макроса на следующей строке.

Я (кажется, я) видел компиляторы, которые включают новые строки в расширенные макросы в выводе списка - для вашей выгоды. Это полезно только нам, беднякам, читающим расширенные макросы, чтобы попытаться понять, что мы действительно просили компилятор. это не имеет никакого значения для компилятора.

Языки C & C ++ одинаково обрабатывают все пробелы вне строк. Просто как разделитель.

4 голосов
/ 19 сентября 2008

Компилятор C знает о пробелах, но он не различает пробелы, табуляции или новые строки.

Если вы имеете в виду, как у меня есть новая строка внутри макроса, то:

#define SOME_STRING "Some string\n with a new line."

будет работать.

0 голосов
/ 19 сентября 2008

Используйте \ в конце строки. Я видел много макросов C, где они используют do ... while (0)

#define foo() do \
{
  //code goes here \
  \
  \
}while(0);

Кроме того, не забывайте использовать скобки во многих случаях.

Пример:

#define foo(x) a+b
//should be
#define foo(x) (a+b)
0 голосов
/ 19 сентября 2008

Не совсем уверен, что вы спрашиваете здесь. Хотите макрос в несколько строк?

#define NEWLINE_MACRO(x) line1 \
line2 \
line3

Кроме того, если вы хотите включить литерал в макрос:

#define NEWLINE_MACRO(x) ##x

то, что вы положили в x, будет заменено на ## x, поэтому:

NEWLINE_MACRO( line1 ) // is replaced with line1

Это может быть полезно для создания пользовательских глобальных функций, тогда просто нужно изменить часть имени функции.

Также:

#define NEWLINE_MACRO(x) #x // stringify x

Поставит кавычки вокруг x

0 голосов
/ 19 сентября 2008

Используйте \, вот так:

#define my_multiline_macro(a, b, c) \
if (a) { \
    b += c; \
}
...