当我在禁用宏时出现以下代码时,我正在使用宏来启用/禁用跟踪:

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/

10-13 04:26