为什么预处理器需要大括号才能有语句?
Why are braces needed for preprocessor in order to have statement?
有这个代码:
#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: error: expected expression before ‘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)); })
编译无误。
但唯一的变化是添加了大括号。那么为什么需要它们呢?预处理器假设什么是语句? (If only means being in braces.)我看到其他宏函数只在括号中声明(没有大括号),那么为什么这个应该有?
预处理器指令不涉及此问题。问题是:
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 一个 语句表达式 是一个表达式后跟一个 ;
.
如果你编译发布的代码片段,你确实会得到一个错误,因为宏被定义为 #define GREATER(a, b, res) ( \ /* no braces here */
并且片段的其余部分被解析为单独的源代码行,因为 \
不是 #define
行的最后一个字符。
你应该小心评论的位置。
更一般地说,asm
语句不是表达式,而是语句,因此不能出现在括号之间。如果你想在表达式上下文中使用宏,你必须通过用 ({
和 })
将语句转换为 statement-expression,一个 gcc扩展名,就像 asm
语句一样。对于要在表达式上下文中使用的结果,您必须指定值:
/* used braces here - correct */
#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)); res; })
最后,计算 a
和 b
中较大者的汇编代码效率低下。编译器可能会从 res = greater(a, b)
生成更好的代码,其中 greater
定义为 static inline int greater(int a, int b) { return a > b ? a : b; }
有这个代码:
#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: error: expected expression before ‘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)); })
编译无误。 但唯一的变化是添加了大括号。那么为什么需要它们呢?预处理器假设什么是语句? (If only means being in braces.)我看到其他宏函数只在括号中声明(没有大括号),那么为什么这个应该有?
预处理器指令不涉及此问题。问题是:
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 一个 语句表达式 是一个表达式后跟一个 ;
.
如果你编译发布的代码片段,你确实会得到一个错误,因为宏被定义为 #define GREATER(a, b, res) ( \ /* no braces here */
并且片段的其余部分被解析为单独的源代码行,因为 \
不是 #define
行的最后一个字符。
你应该小心评论的位置。
更一般地说,asm
语句不是表达式,而是语句,因此不能出现在括号之间。如果你想在表达式上下文中使用宏,你必须通过用 ({
和 })
将语句转换为 statement-expression,一个 gcc扩展名,就像 asm
语句一样。对于要在表达式上下文中使用的结果,您必须指定值:
/* used braces here - correct */
#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)); res; })
最后,计算 a
和 b
中较大者的汇编代码效率低下。编译器可能会从 res = greater(a, b)
生成更好的代码,其中 greater
定义为 static inline int greater(int a, int b) { return a > b ? a : b; }