【问题标题】:C macro that voids variable length input arguments使可变长度输入参数无效的 C 宏
【发布时间】:2021-08-11 14:48:55
【问题描述】:

有没有办法定义一个使变量参数列表无效的宏?

#define VOID_ARGS(...) ((void)##__VA_ARGS__)

当警告被视为错误时,用例是用于抑制编译器错误 [-Werror=unused-value] 的 void 参数:

#define DEBUG 1
#ifdef DEBUG
    #define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
    #define func(fmt, ...) VOID_ARGS(fmt, ##__VA_ARGS__)
#endif

【问题讨论】:

  • “空白”是什么意思?如果您不想使用参数,请不要使用__VA_ARGS__。另请注意,##__VA_ARGS__ 是非标准 gcc 扩展。
  • 您到底想达到什么目标?请发布一个示例,您希望如何使用这样的宏
  • 大概 OP 想告诉编译器没有使用参数,这样它就不会抱怨或发出警告。这有时可以在函数体中使用 (void)unused; 来完成,并且 OP 希望有一个可变参数宏来为多个变量执行此操作。
  • #define func(fmt, ...) 后面没有任何内容怎么样,例如一个空的宏?那应该用;替换func("abc", 4, 3, "bla");
  • 编译器会抱怨未使用的宏参数吗?

标签: c macros preprocessor variadic-macros


【解决方案1】:

这是否让您知道如何解决该问题?

调试.h:

extern int dbg_func(const char *format, ...);

//Does nothing
extern int ignoreDebug(const char *format, ...);


#define DEBUG 1

#ifdef DEBUG
    #define func(fmt, ...) dbg_func(fmt, ##__VA_ARGS__)
#else
    #define func(fmt, ...) ignoreDebug(fmt, ##__VA_ARGS__)
#endif

debug.c:

int ignoreDebug(const char *format, ...)
{
  (void)format;
  return 0;
}

int dbg_func(const char *format, ...)
{
  TODO: Some code needs to go here.
  return 0;
}

【讨论】:

  • 嗯,如果解决方案适用于 op,为什么要投反对票?如果在 debug.h 中将ignoreDebug() 定义为static int 甚至static inline int,则可能会避免额外的调用。优化器应该意识到调用是一个 NOP 并将其优化掉。
  • 感谢@IngoLeonhardt
【解决方案2】:

与其尝试将调试逻辑放在函数声明中,不如将其添加到函数体中:

int dbg_func(const char *format, ...)
{
#ifdef DEBUG
    // normal debug logic
#else
    (void)format;
    return 0;
#endif
}

【讨论】:

  • 根据具体情况,启用或禁用调试的static 布尔值可能会更好。
  • @12431234123412341234123 static volatile atomic 一个可能会更好。我可能是偏执狂,但我知道编译器会来找我。哎呀,您可以将其设为 int 并使用它来设置当前的调试/日志记录级别...
【解决方案3】:

我找到了一种只使用处理器的方法。这个想法来自这个答案https://stackoverflow.com/a/11763277/6082851 这个想法是定义一堆使参数无效的宏,每个可能的参数数量一个宏。使用__VA_ARGS__,可以根据参数的数量选择正确的宏。可悲的是,我没有找到一种使其递归的方法,以便将有限数量的宏用于任意数量的参数,我发现的唯一方法是为每个可能的参数数量定义一个宏。但它可以扩展到任意数量。

#include <stdio.h>

#ifndef DEBUG
  #define DEBUG 1
#endif

#if DEBUG
  #define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)
#else
  //GET_MACRO will get the 6. argument
  #define GET_MACRO(a,b,c,d,e,f,...) f
  //Macros that void a number of arguments
  #define SET_VOID0()  
  #define SET_VOID1(a)          (void)a;
  #define SET_VOID2(a,b)        (void)a;(void)b;
  #define SET_VOID3(a,b,c)      (void)a;(void)b;(void)c;
  #define SET_VOID4(a,b,c,d)    (void)a;(void)b;(void)c;(void)d;
  #define SET_VOID5(a,b,c,d,e)  (void)a;(void)b;(void)c;(void)d;(void)e;
  
  //Void all arguments to avoid compiler warnings.
  //SET_VOID5 is used when there are 5 arguments used, SET_VOID4 when 4 are used, ...
  #define DEBUG_PRINT(...)     GET_MACRO(__VA_ARGS__, SET_VOID5, SET_VOID4, SET_VOID3, SET_VOID2, SET_VOID1, SET_VOID0)(__VA_ARGS__)
#endif



int main(void)
  {
    int foo=5;
    int bar=3;
    DEBUG_PRINT("Foo %i Bar %i\n",foo,bar);
    return 0;
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-06
    • 2014-01-05
    相关资源
    最近更新 更多