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