带有__va_args__和括号的宏出错

时间:2017-03-26 17:37:32

标签: c macros c-preprocessor

我已经从互联网上下载并重新编译了一个图书管理员,由于非法指针地址而导致核心转储。

从源头看,所涉及的陈述是:

#define E_DEBUG(level, ...) \
    if (err_get_debug_level() >= level) \
        err_msg(ERR_DEBUG, FILELINE, __VA_ARGS__)
#define E_DEBUGCONT(level, ...) \
    if (err_get_debug_level() >= level) \
        err_msg(ERR_DEBUG, NULL, 0, __VA_ARGS__)

和崩溃的行:

E_DEBUGCONT(1, (" %d", i));

事实上,编译器正在警告它:

In file included from ptm_mgau.c:56:0:
ptm_mgau.c: In function ‘ptm_mgau_calc_cb_active’:
ptm_mgau.c:317:30: warning: left-hand operand of comma expression has no effect [-Wunused-value]
         E_DEBUGCONT(1, (" %d", i)); 
                              ^
/home/pma/actual/pocketsphinx/pocketsphinx-5prealpha/../sphinxbase-5prealpha/include/sphinxbase/err.h:142:37: note: in definition of macro ‘E_DEBUGCONT’

ptm_mgau.c:317:24: warning: passing argument 4 of ‘err_msg’ makes pointer from integer without a cast [-Wint-conversion]
         E_DEBUGCONT(1, (" %d", i)); 
                        ^
/home/pma/actual/pocketsphinx/pocketsphinx-5prealpha/../sphinxbase-5prealpha/include/sphinxbase/err.h:142:37: note: in definition of macro ‘E_DEBUGCONT’

/home/pma/actual/pocketsphinx/pocketsphinx-5prealpha/../sphinxbase-5prealpha/include/sphinxbase/err.h:159:1: note: expected ‘const char *’ but argument is of type ‘int’
 err_msg(err_lvl_t lvl, const char *path, long ln, const char *fmt, ...);

编译器非常准确:在表达式中( " %d", i )表示忽略"%d"并导致i的值。后者,这个我被用作指针,导致崩溃。

代码的作者似乎期望宏扩展产生这一行:

if (err_get_debug_level() >= level) \
    err_msg(ERR_DEBUG, NULL, 0, " %d", i)

但预处理器产生:

if (err_get_debug_level() >= level) \
    err_msg(ERR_DEBUG, NULL, 0, ( " %d", i) )

有什么方法可以解决这个问题,更改宏定义而不是逐个遍历所有DEBUG语句(数百个)?

**附录**

重现问题的最小例子是编译并执行以下代码:

#include <stdio.h>
#include <stdarg.h>

#define ERR_DEBUG 1
#define FILELINE  __FILE__ , __LINE__

void err_msg(int lvl, const char *path, long ln, const char *fmt, ...) {

    char msg[1024];

    va_list ap;

    va_start(ap, fmt);
    vsnprintf(msg, sizeof(msg), fmt, ap);
    va_end(ap);

    printf("%s\n",msg);

}

#define E_DEBUG(level, ...) \
        err_msg(ERR_DEBUG, FILELINE, __VA_ARGS__)

int main ( void ) {
  E_DEBUG(1,("%d",14));
}

1 个答案:

答案 0 :(得分:0)

这样的东西
#define PASTE(...) __VA_ARGS__

/*PASTE __VA_ARGS__ */

将删除括号,但它取决于总是的括号。

应用于您的示例:

#define PASTE(...) __VA_ARGS__


#define E_DEBUG(level, ...) \
    if (err_get_debug_level() >= level) \
        err_msg(ERR_DEBUG, FILELINE, PASTE __VA_ARGS__)

#define ERR_DEBUG 1
#define FILELINE  __FILE__ , __LINE__

int err_get_debug_level(void);
void err_msg(int lvl, const char *path, long ln, const char *fmt, ...);


int main ( void ) {
  E_DEBUG(1,("%d",14));
}

编译。