如果条件为假,则使用无操作的函数式宏

时间:2019-03-17 15:53:07

标签: c c-preprocessor

假设我在代码的多个位置具有以下构造,并且希望使我的代码更易读:

#if HAVE_LIBFOOBAR
    foobar_func(data);
#endif

我当时正在考虑为此编写一个函数样式的宏,该宏将处理条件语句,使代码中的出现看起来像是常规函数调用:

    foobar_func_if_available(data)

如果条件为true,则将其替换为对实际函数的调用,否则将为空操作。

因此,类似:

#if HAVE_LIBFOOBAR
#define foobar_func_if_available(x) foobar_func(x)
#else
#define foobar_func_if_available(x) {}
#endif

问题:

  • {}是否可以不操作?避免产生意料之外的影响(例如在未括弧的if语句中使用)是否安全?如果没有,我该怎么用?
  • 我是否必须将两个独立的#define包裹在条件语句中,或者是否有另一种方法可以做到(一个#define在函数样式宏中包含条件语句)?

编辑:有人建议这是another question的副本,但我认为并非如此:另一个问题问“此结构解决了什么问题”,我的问题是“什么结构将解决我的问题”。确实,另一个问题可以解决我的问题,但不能涵盖我问题的所有方面。

3 个答案:

答案 0 :(得分:1)

您无法仅凭一个#define来实现。

您不需要{}作为无操作,您可以通过多种方式定义一个空表达式:

#define foobar_func_if_available(x)
#define foobar_func_if_available(x) ;
#define foobar_func_if_available(x) do{}while(0)

在某些情况下,这两种情况都可能导致语法问题,但是对于void函数,都不可能引起问题-但是,对于非void函数,解决方案将失效。

一种完全避免类似于函数的宏的更好解决方案是有条件地定义函数主体:

void foobar_func( int n )
{
    #if defined HAVE_LIBFOOBAR
       // do something
    #else
       // do nothing
    #endif
}

空函数是否不导致任何代码取决于编译器和应用的优化级别,但是重要的是,该代码将在对foobar_func()的调用有效的所有情况下在语法上起作用。担心是否不进行操作可能会流失一些小东西。

答案 1 :(得分:1)

创建一个虚拟函数,并在其上定义#define点(有条件):


#if HAVE_LIBFOOBAR
  #define foobar_func_if_available(x) foobar_func(x)
#else
  int dummy(int ignored)
  {
  return 0;
  }
  #define foobar_func_if_available(x) dummy(x)
#endif

或者只是:

#define foobar_func_if_available(x) 0

答案 2 :(得分:1)

((int)0)((void)0)这样的宏可能是最灵活/最安全的无操作宏。它们很灵活,因为您可以使用它们 (与do{}while(0)不同)中,它们不会像if-else{}那样破坏;

{}(或;)宏如何中断if-else的示例:

#define foo() {}
if(1) foo(); else bar(); //syntax error because if(1) {}; else bar(); was pasted

如果宏应模拟整数返回函数,则最好在普通整数常量上使用强制转换的整数文字,因为整数常量(尤其是零)可在更多情况下使用(大小写标签,位域大小,数组大小,null指针常量),而不是非常量整数表达式。

您不需要像下面这样具有两个宏:

#if HAVE_LIBFOOBAR
    #define foobar_func_if_available(x) foobar_func(x)
#else
    #define foobar_func_if_available(x) ((void)0) /*if foobar_func returns void*/
#endif

您可以将条件放在宏中:

#define foobar_func_if_available(x) \
    (HAVE_LIBFOOBAR?foobar_func(x):((void)0))

即使是非常笨拙的编译器也应该能够优化常量条件输出。

但是,如果您依靠空HAVE_LIBFOOBAR来计算0中的#if,则上述方法将不起作用-HAVE_LIBFOOBAR必须为整数。

( 您可以

#if !HAVE_LIBFOOBAR
    #undef HAVE_LIBFOOBAR
    #define HAVE_LIBFOOBAR 0
#endif
#define foobar_func_if_available(x) \
        (HAVE_LIBFOOBAR?foobar_func(x):((void)0))

将空的HAVE_LIBFOOBAR标准化为0,但是除非您重复使用现在确定的HAVE_LIBFOOBAR的定义,否则看起来好像不必要地复杂了原来的两个foobar_func_if_available宏。 )