如何编写扩展以包含换行符的 cpp 宏?
7 回答
我正在从事一个大型项目,该项目涉及许多预处理器宏函数来合成任何无法被模板替换的代码。相信我,我熟悉各种模板技巧,但只要没有可以直接创建代码的标准化、类型安全的元编程语言,我们就必须坚持使用好的旧预处理器及其繁琐的宏来解决一些问题如果没有,则需要编写十倍以上的代码。一些宏跨越多行,在预处理代码中很难阅读。因此,我想到了解决该问题的方法,我想出的是以下内容:
假设我们有一个跨越多行的 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)
如果我需要调试宏,我只需取消注释MyImplementation.cppPRINT_VARIABLE
中定义宏HAVE_MULTILINE_DEBUGGING
的行。生成的代码当然不会编译,因为宏结果未定义,这会导致它保留在已编译的代码中,但是可以对其进行预处理。__NL__
现在的关键步骤是__NL__
使用您最喜欢的文本编辑器将预处理器输出中的字符串替换为换行符,瞧,您最终会在预处理后得到替换宏的结果的可读表示,这与编译器所看到的完全相同,除了对于人为引入的换行符。
这不可能。只有当您查看列表文件或预处理器输出时,它才会相关。
编写宏以使其更易于阅读的一种常用技术是使用 \ 字符将宏继续到下一行。
我(相信我)已经看到编译器在列表输出的扩展宏中包含新行 - 为了您的利益。这仅对我们这些阅读扩展宏以试图理解我们真正要求编译器做什么的可怜人有用。它对编译器没有影响。
C 和 C++ 语言以相同的方式处理字符串之外的所有空格。就像一个分隔符。
C 和 C++ 编译器会忽略不带引号的空格(除了 > > 模板问题),因此让宏发出换行符并没有真正意义。您可以通过用反斜杠结束宏的每一行来使宏跨越多行,但这不会输出换行符。
C 编译器知道空格,但它不区分空格、制表符或换行符。
如果您的意思是如何在宏的字符串中添加新行,那么:
#define SOME_STRING "Some string\n with a new line."
将工作。
不太清楚你在这里问什么。你想要一个多行的宏吗?
#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 周围加上引号
在行尾使用 \。我见过很多使用 do...while(0) 的 C macos
#define foo() do \
{
//code goes here \
\
\
}while(0);
此外,请记住在许多情况下使用括号。
例子:
#define foo(x) a+b
//should be
#define foo(x) (a+b)
使用\
,像这样:
#define my_multiline_macro(a, b, c) \
if (a) { \
b += c; \
}