为啥我的简单 C 宏不起作用?
Posted
技术标签:
【中文标题】为啥我的简单 C 宏不起作用?【英文标题】:Why doesn't my simple C macro work?为什么我的简单 C 宏不起作用? 【发布时间】:2016-04-02 21:23:34 【问题描述】:我想做一个简单的宏,像这样调用 printf() 两次
#ifdef ENABLE_DEBUGPRINTF
#define DEBUGPRINTF(msg) printf("At sim_time = %f:", sim_time); printf(msg);
#else
#define DEBUGPRINTF(msg) //evalutes to nothing
#endif
现在当我打电话时
DEBUGPRINTF("Processed event type: %d with value %f\n", id, data)
它正确地打印了第一部分“At sime_time = ...”,但后面的部分“Processed events ...”错误地打印了 id 和 data 的值。
同时
printf("Processed event type: %d with value %f\n", id, data);
正确打印值。
当我尝试通过准确写出我认为宏将评估为的内容来执行它时,我做到了。
printf("At sim_time = %f:", sim_time); printf("Processed event type: %d with value %f\n", id, data);
这将正确打印所有内容!那么为什么我的宏没有对此进行评估?
【问题讨论】:
@PaulGriffiths D'oh 当然。抱歉,我不习惯预处理器指令。出于某种原因,我认为括号内的所有内容都将包含在“msg”中。 不相关,但最好在多指令宏周围加上大括号:#define DEBUGPRINTF(msg, id, data) etc...
。否则,当宏在if
之后使用时,您可能会感到意外。
@user1320881:这仍然会导致错误的代码,例如在if
声明中。正确执行此操作的常用方法是包装到 do .. while ( 0 )
虚拟循环中。每个现代编译器都会识别这种模式并优化循环。
@Olaf:在这种情况下,由于printf
调用是表达式,最好用逗号分隔它们并将整个内容括在括号中(并去掉分号)。 do ... while(0)
技巧让您可以在需要声明的任何地方使用宏,但如果扩展是表达式,则更加灵活。
【参考方案1】:
因为您想要并且正在使用常规 printf
的全部灵活性,所以您想要的是带有 variadic
参数的宏:
#ifdef ENABLE_DEBUGPRINTF
#define DEBUGPRINTF(msg...) \
printf("At sim_time = %f:", sim_time); printf(msg);
#else
#define DEBUGPRINTF(msg...) /*evalutes to nothing*/
#endif
我以前做过很多次,我建议用do while (0)
封装:
#ifdef ENABLE_DEBUGPRINTF
#define DEBUGPRINTF(msg...) \
do \
printf("At sim_time = %f:", sim_time); \
printf(msg); \
while (0)
#else
#define DEBUGPRINTF(msg...) //evalutes to nothing
#endif
这使您可以执行以下操作:
if (showit)
DEBUGPRINTF("hit the showit point -- showit=%d\n",showit);
因此,使用宏的代码不必知道它实际上是两个语句[或没有]
更新:
DEBUGPRINTF(msg...)
不符合标准,而是一些旧版编译器扩展。您在省略号之前漏掉了一个逗号。
也许,但就我个人而言,我仍然更喜欢它,并且已经在生产代码中使用它 10 多年了。
但是,对于那些可能希望使用替代方法的人来说,这里有一些资源:
-
https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
https://en.wikipedia.org/wiki/Variadic_macro
【讨论】:
DEBUGPRINTF(msg...)
不符合标准,而是一些旧版编译器扩展。您在省略号之前漏掉了一个逗号。【参考方案2】:
您声明 DEBUGPRINTF
接受一个参数,但随后您传递了三个参数,所以它当然不会像您期望的那样工作。
msg
在你的第一个例子中只是"Processed event type: %d with value %f\n"
,你的第二个printf()
调用只是为%d
和%f
拉垃圾,因为你的宏从来没有告诉它任何关于id
或data
,所以他们永远不会被传递给printf()
。
你想要这样的东西:
#define DEBUGPRINTF(msg, id, data) printf("At sim_time = %f:", sim_time); printf(msg, id, data);
或者,如果您需要更灵活的东西,可以使用可变参数宏。
【讨论】:
如果用作像if
这样的语句的主体,这仍然会引起问题。【参考方案3】:
使用双(嵌套)定义:
#define FIRST printf("…")
#define DEBUGMSG(msg) FIRST;printf(msg)
这在定义中有一个参数,在实现中有一个参数。
【讨论】:
这只不过是 OP 已经拥有的。它根本无法解决 OP 的实际问题。如果您按照 OP 的要求尝试DEBUGPRINTF("Processed event type: %d with value %f\n", id, data)
,那么您会发现您的解决方案将以与 OP 所经历的完全相同的方式失败。以上是关于为啥我的简单 C 宏不起作用?的主要内容,如果未能解决你的问题,请参考以下文章