2017-02-14 67 views
0

我在尝试将宏常量作为参数传递给宏函数时遇到问题。以其他宏为参数调用C宏

考虑下面的代码 -

#define ERROR 10 
#define MAIN "Main:" 

#define LOG(lvl,mod,fmt,...) \ 
    char msg[256] = {0}; \ 
    snprintf(msg, 256, "%s: %d: "fmt,mod,lvl,##__VA_ARGS__) 

int main() 
{ .... 
    LOG(ERROR, MAIN, "This is a log statement.\n"); // Doesn't compile 
    LOG(10, "Main:", "This is a log statement.\n"); // Compiles 
    .... 
} 

第二日志语句编译但第一个日志语句生成以下编译错误 -

error: expected `)' before ‘;’ token 
error: expected primary-expression before ‘,’ token 
error: expected `;' before ‘)’ token 

这究竟是为什么?我希望能够定义一组记录级别和模块常量,并在调用LOG()宏时使用它们。

+3

完全无关的(当前)的问题,而是你的'LOG'宏将不能用一个简单的'if'语句或循环体不工作明确的护腕。有一个原因是,大多数人在创建多语句宏时用'do {...} while(0)'来包围它们。 –

+6

该宏被破坏,因为它会在同一范围内声明多个“msg”变量。 – Droppy

+1

至于如何解决您的问题,请告诉编译器在运行预处理器后停止,以查看宏扩展创建的代码。 –

回答

0

有两个问题,我可以看到:

  1. 您将具有相同的范围内的多个msg变量。
  2. 您错过了一个逗号(正如@Ninetainedo指出的那样)。
  3. 你对格式化的字符串不做任何处理。

我宁愿声明一个全局的logger()函数,它接受日志级别并使用宏缩短调用它。

+0

缺少的逗号不是问题。它允许连接字符串常量。 –

+0

@JohnnyMopp对。纠正。 – Droppy

+0

假设真正的代码确实用'msg'做了某些事情,但它与这个问题无关,因此被省略了。 – rici

0

你的宏的一个问题是它在一段代码中的随机点声明了一个变量,C89不允许这样做:你只能在块的顶部声明变量。即使使用C99编译器,问题也不会消失,因为现在可以在同一范围内引入多个同名的声明,这是禁止的。

可以使用do/while(0) trick来解决这个问题:

#define LOG(lvl,mod,fmt,...) do {\ 
    char msg[256] = {0}; \ 
    snprintf(msg, 256, "%s: %d: "fmt,mod,lvl,##__VA_ARGS__) \ 
} while(0) 
+0

它也不能解释为什么第二个变体编译时,当OP没有使用前两个参数的宏时。 –

+1

@Someprogrammerdude最可能的原因是OP代码前面有一些不编译的东西,他有'.....',因为当你自己编译他的代码时,它编译得非常好([demo] (http://ideone.com/F9TW7H))。 – dasblinkenlight

+0

在我的实际代码中,我从构造函数中调用了这个LOG宏,它是构造函数中的第一条指令。 此外,这些宏在不同的.h文件中定义,而不是从其被调用的位置。 .h文件具有与我上面的示例相同的宏定义。宏定义的排序与此有什么关系? – siri