多行DEFINE指令?

65

我不是专家,请温柔一点。这两段代码有什么区别吗?

#define BIT3 (0x1
<
<
3)
static int a;

#define BIT3 (0x1 << 3) static int a;

还有,有没有一种方法可以在一行中编写第一个问题?使用这种多行风格的目的是什么?以下代码好吗?

#define BIT3 (0x1 << 3)
static int a;

第一个片段有两个连续的<(小于)运算符和没有<<(移位)运算符。还有一个类似对象的宏,值为(0x1,后面跟着3行毫无意义的代码(它们不是宏定义的一部分;必须在这些行尾部加上反斜杠),然后是声明语句。第二个片段相当不同,但更加难以使用。(0x1 << 3)表达式本身没问题,但接下来的static定义只是一个语法错误;你需要在括号关闭后加上分号才有可能成功。所以它们是不同的!! - Jonathan Leffler
3个回答

110

如果宏非常复杂,将其全部写在一行上会很难阅读,这时多行宏很有用(尽管拥有非常复杂的宏是不可取的)。

通常情况下,您可以使用换行字符\编写多行定义。例如:

#define MY_MACRO    printf( \
    "I like %d types of cheese\n", \
    5 \
    )

但是你不能像第一个示例那样这样做。你不能这样分割标记;左移操作符<<必须始终在没有任何分隔空格的情况下编写,否则它将被解释为两个小于运算符。所以也许:

#define BIT3 (0x1 \
    << \
    3) \
    static int a;

现在,它与您的第二个示例等效。

[虽然我不确定那个宏怎么可能有用!]


实际上,这是一份关于为不同嵌入式设备编写跨平台代码的指南。这是“定义”第三位的安全方式,因为不同的系统可能会对给定变量类型使用不同数量的字节。 - Adam S
6
@Adam: 嗯,我不明白!什么时候(0x1 << 3) static int a会是有效语法? - Oliver Charlesworth
抱歉,我以为我理解了你的回答,直到看到“[虽然我不确定那个宏如何有用!]”为止。我必须承认,在这种情况下,我不知道“那个”指的是什么。如果#define BIT3 (0x1 << 3) static int a;不是有效的语法,那么它就不是一个宏(我恐惧地想象它可能在某个地方编译)。在这种情况下,“那个宏”不能指代它,尽管你的简洁评论。 - ebyrob
@ebyrob - 这个答案已经有6年了,所以我也不太确定 :) 我想我当时的意思是,虽然 #define BIT3 (0x1 << 3) static int a; 是一个有效的宏定义,但它生成的代码是无效的(因此该宏没有任何用处)。 - Oliver Charlesworth
@OliverCharlesworth 好的,你向我展示了\\确实是多行宏的正确行终止符,但我可以理解提问者可能会对高级主题感到有些困惑。我不确定我是否认为一个“宏”如果不能在定义之外存在而不会编译错误就是“有效的宏”(除非生成这样的错误是其明显目的),但我偏离了主题。 - ebyrob
如果我想要它包含几行呢?也就是说,我希望它的扩展能够跨越几行? - Royi

21
例如:
#define fact(f,n)   for (f=1; (n); (n)--) \
                      f*=n;

您可以使用\字符将行分离。请注意,这不是特定于宏的。每当您想要换行时,可以在代码中添加\字符。


有趣。除了宏之外,它还有其他有用的用途吗? - Oliver Charlesworth
当然可以。比如你有一个非常长的printf语句或其他语句,但你想手动换行,这时它就非常方便了。 - phoxis
2
是的,当不允许连接字符串常量时,它非常方便。这是不被允许的:"a string" " continued"。 - Prof. Falken
@Oli Charlesworth,现在我(也许)引起了您的注意,您看到这个了吗:https://dev59.com/yHA75IYBdhLWcg3wsrWD#5564577 - Prof. Falken
如果我想要它包含几行呢?也就是说,我希望它的扩展能够跨越几行? - Royi

8
第一个应该不起作用。行应该用反斜杠和换行符隔开。就像这样:
#define SOME_MACRO "whatever" \
"more" \
"yet more"

6
更重要的是,行终止符应该用反斜杠进行转义。如果在反斜杠后面加上空格,预处理器会出现一些极端的错误。 - JUST MY correct OPINION
@Royi 如果你想要多行字符串字面量,C++ 是可以做到的(但 C 不行)。https://dev59.com/1HNA5IYBdhLWcg3wAIpP#5460235 - Prof. Falken
但是我需要在预处理阶段使用字符串,而不是在程序中。考虑在一个#define ALL_PRAGMAS中定义几个#pragma(每个都在自己的一行上)。 - Royi
@Royi,我不确定你的意思。在每行末尾加上\会有帮助吗?也许你应该开一个问题。 - Prof. Falken
假设您有#pragma somePragmaA,然后换行符#pragma somePragmaB,然后换行符#pragma somePragmaC。 这些都是pragma,因此每个必须在新行中。 假设您在代码中经常使用它们,因此希望创建一个单一的宏,该宏将通过预处理器展开为它们。这可行吗? - Royi
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接