Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/148.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 让宏定义为函数返回值是一种不好的做法吗?_C++_C_Macros - Fatal编程技术网

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

C++ 让宏定义为函数返回值是一种不好的做法吗?,c++,c,macros,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) // fu

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

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

#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;
}
我很好奇宏的好处(在我的代码中很多地方都会用到)是否会超过上面提到的缺点。 除了简单地扩展(不使用宏)之外,还有其他更好的选择吗?

标准答案是“不要使用宏”;但这往往有点简单化。有时候,他们可以大大减少样板文件中的冗长内容,否则你就不会有这些内容了

那么,为什么不将事实编码到宏名称中呢?e、 g.
在发生故障时写入或返回
。它可能有点冗长,但不太可能让代码的读者绊倒。

制作一个两步宏:

#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\u CHK(file,param,return false)

是的,这很糟糕。使用
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语句(与其他语句中的宏一样,向上投票的答案),则会产生意外的副作用,例如:

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

 if (a) DONT_DO_THIS(x)
 else something_else();
时,您会期望执行其他操作!a
,但宏实际扩展为:

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

a&&x
时,而不是当
时,会执行其他操作!程序员想要的

在宏中隐藏控制流不是很常用,因此它可能会让开发人员感到困惑,因为他们必须理解或调试您的代码

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

// 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;
}


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

我想在这里给你+0.5。你的建议是完全正确的,但宏观回报方法有一种味道,更好的答案应该包括一些替代方法+1.:)@乔纳森:是的,我考虑过。但有时你真的只是想结束这种单调乏味的模式,而助手函数却不能做到这一点。这很公平。尽管如此,这条路仍然是利龙。是的,谢谢你理解它的用法和有效的建议。命名可以做很多事情!同意-只要宏名称中包含动词
RETURN
,这就足够警告了。这是如何解决问题的?@Oli如果你想让它表明你正在返回false,你可以使用类似
WRITE\u CHK(file,param,RETURN false)
。是的,确实如此。我想如果你的答案是这样的话会更好@奥利编辑。我多次使用这个宏模式,它的第二个本质答案本身很复杂,但通过奥利的评论和你的答案,我想我明白你在说什么了。很有趣,谢谢。通常的C++方法是让“写”函数本身在错误上抛出异常,而不是不断检查返回代码。有同样的“潜在意外提前返回”问题,但任何使用异常的程序也是如此……我想要一个c兼容的解决方案。请告诉我为什么我的问题被否决,以便我可以改进未来的问题。人们可能否决了你的问题,因为它似乎是主观的。以“这是不是坏习惯”开头的问题在这里通常会受到不好的评价。事实上,有人将其标记为“不具建设性”或离题。我恰好不同意这一点,因为我认为你在这里提出了一个有用的问题,而且有一些很好的答案(比如奥利的答案)不仅仅是个人观点或可能引发争论。我赞成保留此选项,但您可能需要稍微改写标题。宏的另一个问题是调用端的异常语法。它不能替换正确的语句,您就有了悬而未决的
else
问题。你可以只附加
else(void)0
来去掉这两个。你是认真的吗?这在消除意外方面有什么好处?我当然是认真的。函数中的两个退出点都是可见的,
fail
标签告诉您发生了什么。此外,与使用fsmc的
WRITE_CHK
等宏不同,它写入、检查并可能返回(然后是类似的
BAR_CHK
用于BAR等),有一个
检查
宏。我这样称呼是为了效仿他的例子,但我会使用类似于
fail\u check
,加强宏和标签之间的联系。@Foo-Bah它概括起来比你自己的答案好得多。我不认为你对使用
while
循环的标准模式的解释是为什么有人对此投了反对票……显然不可能,因为解释是在投反对票之后。你的意思是什么?