为什么';这不是我简单的C宏工作吗?
我想制作一个简单的宏,像这样调用printf()两次为什么';这不是我简单的C宏工作吗?,c,macros,preprocessor-directive,C,Macros,Preprocessor Directive,我想制作一个简单的宏,像这样调用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 valu
#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)
它正确地打印了第一部分“在sime_时间=…”,但后面部分显示“已处理的事件…”时,它错误地打印了id和数据的值
同时
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);
这一切打印正确!那么为什么我的宏不对此进行求值呢?您将
DEBUGPRINTF
声明为接受一个参数,但随后将其传递三个参数,因此它当然不能像您预期的那样工作
在第一个示例中,msg
只是“处理的事件类型:%d,值为%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 (showit)
DEBUGPRINTF("hit the showit point -- showit=%d\n",showit);
或者,如果您需要更灵活的方法,可以使用可变宏。使用双(嵌套)定义:
#define FIRST printf("…")
#define DEBUGMSG(msg) FIRST;printf(msg)
这在定义中有一个参数,在实现中有一个参数。因为您想要并且正在使用常规
printf
的全部灵活性,所以您想要的是一个带有可变参数的宏:
#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)
进行封装:
这允许您执行以下操作:
#define DEBUGPRINTF(msg, id, data) printf("At sim_time = %f:", sim_time); printf(msg, id, data);
if (showit)
DEBUGPRINTF("hit the showit point -- showit=%d\n",showit);
因此,使用宏的代码不必知道它实际上是两条语句[或没有]
更新:
DEBUGPRINTF(msg…
不符合标准,但有一些旧式编译器扩展。你在省略号前漏掉了一个逗号
也许吧,但就我个人而言,我仍然更喜欢它,并且已经在生产代码中使用它10多年了
但是,以下是一些可能希望使用替代方法的资源:
@当然是保格里菲斯。对不起,我不习惯预处理器指令。出于某种原因,我将括号内的所有内容都映射到“msg”中。与此无关,但最好在多指令宏周围放上括号,如下所示:#define DEBUGPRINTF(msg,id,data){etch}
。否则,当在if
@user1320881:之后使用宏时,您可能会得到一些惊喜:这仍然会导致错误的代码,例如在if
语句中。正确执行此操作的常用方法是将其包装为do。。而(0)
虚拟循环。每个现代编译器都会识别这种模式并优化循环。@Olaf:在这种情况下,由于printf
调用是表达式,所以最好用逗号运算符将它们分开,并将整个过程括在括号中(并去掉分号)。do。。。while(0)
trick让我们在任何需要语句的地方使用宏,但是如果扩展是表达式,它就更灵活了。这只不过是OP已有的功能而已。它根本无法解决OP的实际问题。如果您按照OP的要求尝试DEBUGPRINTF(“已处理事件类型:%d,值为%f\n”,id,数据)
,则您会发现解决方案将以与OP所经历的完全相同的方式失败。如果之类的语句体使用,DEBUGPRINTF(msg…
不符合标准,则仍会导致问题,但是一些遗留的编译器扩展。你在省略号前漏掉了一个逗号。