代码之家  ›  专栏  ›  技术社区  ›  Michael Mior

在C宏中使用并返回输出

  •  9
  • Michael Mior  · 技术社区  · 15 年前

    我正在尝试检测一些代码来捕获和打印错误消息。目前我使用的宏是这样的:

    #define my_function(x) \
      switch(function(x)) { \
        case ERROR: \
          fprintf(stderr, "Error!\n"); \
          break; \
      }
    

    通常,我从不捕获函数输出,这很好地工作。但我发现了几个案例,其中我还需要 function() . 我尝试了如下操作,但这会产生语法错误。

    #define my_function(x) \
      do { \
        int __err = function(x); \
        switch(__err) { \
          case ERROR: \
            fprintf(stderr, "Error!\n"); \
            break; \
        } \
        __err; \
      } while(0)
    

    我可以声明一个全局变量来保存函数的返回值,但这看起来很难看,而且我的程序是多线程的,所以这可能会导致问题。我希望有更好的解决办法。

    5 回复  |  直到 7 年前
        1
  •  6
  •   Jens Gustedt    15 年前

    这是一个相对复杂的代码,没有太多的理由在宏中使用它。成功 inline (C99)或 static (c89)或者两者都放在头文件中。对于任何合理的编译器,这将产生与宏相同的效率。

        2
  •  44
  •   qrdl    15 年前

    GCC有一个称为 statement expressions

    所以如果定义宏

    #define FOO(A) ({int retval; retval = do_something(A); retval;})
    

    你可以像这样使用

    foo = FOO(bar);
    
        3
  •  4
  •   gusaki    9 年前

    很晚才答复。但同样如此。我同意内联函数更好,但宏确实提供了一些您无法从内联函数中获得的相当有趣的打印功能。我同意@qrdl的观点,如果您对语句进行了一点重组,那么您确实可以使用语句表达式。下面是如何使用宏-

    #define my_function(x, y) ({ \
      int __err = 0; \
      do { \
        __err = function(x, y); \
        switch(__err) { \
          case ERROR: \
            fprintf(stderr, "Error!\n"); \
            break; \
        } \
      } while(0); \
      __err; \
    })
    
        4
  •  2
  •   hopia    15 年前

    抱歉,这是一个编辑…

    1. 我想你只需要大括号。不需要Do..While关键字
    2. 确保反斜杠是每行的最后一个字符(后面没有空格)。
    3. 如果需要从宏中获取err值,只需添加一个参数

    像这样:

     #define my_function(x, out) \
          { \
            int __err = function(x); \
            switch(__err) { \
              case ERROR: \
                fprintf(stderr, "Error!\n"); \
                break; \
            } \
            __err; \
            (*(out)) = _err; \
          }
    

    要保留pass-by-reference c范例,您应该这样调用my_函数:

    int output_err;
    
    my_function(num, &output_err);
    

    这样,以后,如果您决定使我的函数成为一个真正的函数,就不需要更改调用引用。

    顺便说一句,qrdl的“语句表达式”也是一种很好的方法。

        5
  •  -2
  •   The joker    10 年前

    如果函数返回某个值,则无需声明变量,然后可以直接获取该值。例如:

    #define FOO(A) do_something(A)
    

    这里,do_something返回一些整数。然后您可以很容易地使用它,如:

    int a = FOO(a);