当我在禁用宏时出现以下代码时,我正在使用宏来启用/禁用跟踪:
int main()
{
("Hello world");
}
这段代码是有效的,我得到了想要的效果(禁用宏时什么也没有发生),但我无法弄清楚到底发生了什么。编译器是否将括号视为“无名”方法声明?
为了更清楚,代码是:
#ifdef TRACE
#define trace printf("%s %d -> ",__FILE__, __LINE__);printf
else
#define trace
#endif
int main()
{
trace("Hello world");
}
提前致谢。
最佳答案
如果缺少函数名称,如在您的第一个示例中,则它不是“括号运算符”。它只是改变运算符和操作数之间关联的表达式的句法元素。在这种情况下,它只是什么都不做。你拥有的只是一种表达
"Hello world";
其计算结果为
char *
类型的值,并且该值被忽略。您可以将该表达式包含在一对冗余的 ()
中("Hello world");
这不会改变任何东西。
以完全相同的方式你可以写
(5 + 3);
在您的代码中间,并获得一个评估为
8
值的表达式,该表达式立即被丢弃。通常编译器不会为没有副作用的表达式语句生成任何代码。事实上,在C语言中,每个表达式语句的结果都被丢弃了,所以唯一“有意义”的表达式语句是带有副作用的表达式语句。编译器通常非常擅长检测无效果的语句并丢弃它们(有时会发出警告)。
警告可能很烦人,因此编写无效果的表达式语句,例如
"Hello world";
可能不是一个好主意。通常编译器会将对
void
的转换识别为不生成此警告的请求(void) "Hello world";
所以你可以考虑相应地重新定义你的宏。
当然,使用上面的
trace
技术,你必须记住,如果你把一些确实有副作用的东西作为你的宏的参数trace("%d\n", i++);
然后以“禁用”形式显示如下
("%d\n", i++);
(两个子表达式,由逗号运算符链接成一个表达式)。在这种情况下,增加
i
的副作用仍然存在,不会被禁用。整个事情相当于平原i++;
此外,如果您使用函数调用作为参数
trace(get_trace_name());
“禁用”表单看起来像
(get_trace_name());
并且编译器可能不够聪明,无法意识到应该丢弃对
get_trace_name()
的调用。因此,使用宏时要小心。避免带副作用的参数,避免带函数调用的参数,当然,除非您打算在禁用实际跟踪时保留副作用。关于c - C中的括号运算符,下面代码中的作用是什么,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2630166/