让宏定义为函数返回值是不好的做法吗?

时间:2011-08-09 23:39:10

标签: c++ c macros

使用定义的宏来有条件地返回一个值有一个缺点,即仅仅查看客户端代码可能会在宏点处退出。

我正在考虑的用例是写一个值和错误检查,如下所示:

#define WRITE_CHK(file, param)\
if (!write_that_returns_zero_on_fail(file, param)) {\
   handle_error();\
   return false;\
}

客户代码:

bool myfunc()
{
   ...
   WRITE_CHK(file, param) // function might return here
   ...
   return true;
}

我很好奇宏(在我的代码中会在很多地方使用)的好处将超过上面提到的缺点。 除了简单地扩展(不使用宏)之外,是否有其他选择?

4 个答案:

答案 0 :(得分:15)

标准答案是“不要使用宏”;但这通常略显简单。有时情况下,他们可以大大减少你原本没有的样板冗长。

那么,为什么不将事实编码到宏名称中呢?例如WRITE_OR_RETURN_ON_FAILURE。它可能略显冗长,但它不太可能让你的代码的读者绊倒。

答案 1 :(得分:3)

隐藏宏内部的控制流并不常用,因此对于必须理解或调试代码的开发人员来说可能会造成混淆。

我建议完全不使用宏,但如果必须使用它们,请确保控制流部分是显式的。

// assume handle_error returns true
#define WRITE_FAILED(file, param)\
(!write_that_returns_zero_on_fail(file, param) && handle_error())

// macro usage
if(WRITE_FAILED(file, param))
{
    return;
}

要问自己的另一个问题是 - 为什么要在这里使用宏呢?如果是为了隐藏控制流程那么这不是一个好主意。还有其他原因吗?

答案 2 :(得分:1)

制作一个两步宏:

#define WRITE_CHK_(file, param, HANDLER)\
if (!write_that_returns_zero_on_fail(file, param)) {\
    handle_error();\
    HANDLER\
}

#define RFALSE return false;

#define WRITE_CHK(file, param) WRITE_CHK_(file, param, RFALSE)

如果您需要在其他地方进行类似的检查(或直接使用WRITE_CHK(file, param, return false)),您可以制作其他包装。

答案 3 :(得分:-4)

是的,这很糟糕。使用goto

 #define fail_unless(x) do {if(!(x)) goto fail;} while (0)

 int foo()
 {
     fail_unless( my_write(...) );
     fail_unless( bar() );
     return 0;
 fail:
     cleanup();
     return -1;
 }

编辑:如果您因为不了解while循环在那里做什么而进行了低估,那么您应该问一下。它是一种标准技术,用于确保C宏在任何上下文中充当单个语句。如果你的宏扩展为if语句(就像其他的宏,upvoted答案),那么你会得到意想不到的副作用,例如:

 #define DONT_DO_THIS(x) if (!x) { foo; }

 if (a) DONT_DO_THIS(x)
 else something_else();

你期望在!a时执行something_else,但宏实际扩展到的是:

 if (a)
     if (!x) { foo;}
     else something_else();

而且,a && x时会执行something_else,而不是程序员想要的!a