有这段代码:
#define GREATER(a, b, res) ( \ /* no braces here */
asm("cmp %1, %2\n\t" \
"jge 0f\n\t" \
"movl %1, %0\n\t" \
"jmp 1f\n" \
"0:\n\t" \
"movl %2, %0\n" \
"1:" \
: "=r"(res) \
: "r"(a), "r"(b)); )
错误:
c.c:4:2: 错误:'asm' 之前的预期表达式
asm("cmp %1, %2\n\t"\
但是这个(只改变了大括号,其他一切都留下了——代码在其他方面都是正确的):
#define GREATER(a, b, res) ({ \ /* used braces here - correct */
asm("cmp %1, %2\n\t" \
"jge 0f\n\t" \
"movl %1, %0\n\t" \
"jmp 1f\n" \
"0:\n\t" \
"movl %2, %0\n" \
"1:" \
: "=r"(res) \
: "r"(a), "r"(b)); })
编译不会出错。 但唯一的变化是添加了大括号。那么为什么需要它们呢?预处理器假设什么是语句? (如果只意味着在大括号中。)我已经看到其他宏函数只在括号中声明(没有大括号),那么为什么这个应该有大括号?
最佳答案
预处理器指令不涉及此问题。问题是:
asm(…)
是 GCC 对 C 语言的扩展。 GCC 将asm
视为一个语句,它后面必须跟一个;
。- 括号是表达式的一部分。当你写
(…)
时,括号中的内容应该是一个表达式。由于asm
不是表达式,因此(asm(…);)
是一个错误。 - GCC 有一个名为 statement expressions 的扩展名,其中
({...})
有一个类似于表达式的值,但可能包含语句。在({...})
中,您可以将语句放在大括号内,GCC 将对它们求值并使用最后一个表达式语句1 在它们中作为({...})
表达式的值。 (({...})
中的最后一条语句应该是表达式语句,而不是其他类型的语句,就像for
循环一样。)
因此 ({ asm(…); })
被接受为一个表达式。
然而,尽管 GCC 接受它,但它违反了 GCC 文档中“复合语句中的最后一件事应该是一个表达式后跟一个分号……”的声明。看起来您的宏不打算用作表达式;它将结果放入 res
但本身没有值。在这种情况下,您可以通过从原始代码中删除括号使其成为一个简单的语句:
#define GREATER(a, b, res) \
asm("cmp %1, %2\n\t" \
"jge 0f\n\t" \
"movl %1, %0\n\t" \
"jmp 1f\n" \
"0:\n\t" \
"movl %2, %0\n" \
"1:" \
: "=r"(res) \
: "r"(a), "r"(b));
此外,人们通常更喜欢在此类宏中省略最后的 ;
,因为这样宏在源代码中使用时可以像语句一样编写:
GREATER(a, b, res);
不要让习惯于以 结尾的语句的人看起来很奇怪;
:
GREATER(a, b, res)
(虽然在定义中有;
,你仍然可以写成GREATER(a, b, res);
,但是这扩展为有;;
,这可能会导致问题,因为 if (foo) GREATER(a, b, res); else...
将无法将 else
与 if
因为额外的 ;
.)
脚注
1 语句表达式 是一个后跟 ;
的表达式。
关于c - 为什么预处理器需要大括号才能有语句?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60248754/