我试图清理包含数百个函数的遗留代码,其中包含如下所示的实体:
void functionWithSideEffect(Foo* foo)
{
if (foo)
{
// Use `foo' to warm the planet
...
}
}
显然,如果前提条件检查失败,默默地失败并不是最好的主意,所以我想将其重构为:
int functionWithSideEffect(Foo* foo)
{
RETURN_IF_FALSE(foo != NULL, "foo is NULL in functionWithSideEffect!");
// Use `foo' to warm the planet
...
}
以下宏似乎适用于不返回值的函数:
#define RETURN_IF_FALSE(cond, msg) \
do { \
if (!(cond)) { \
LOG("%s\n", (msg)); \
assert((cond)); \
} \
return; \
} while(0)
它具有以下理想的属性:
(不可否认,对于返回void
的函数,在发布版本中进行训练可能并不总是令人满意的。“
对于做返回值的函数,这个宏可以解决这个问题:
#define RETURN_VALUE_IF_FALSE(cond, msg, retval ) \
do { \
if (!(cond)) { \
LOG("%s\n", (msg)); \
assert((cond)); \
} \
return(retval); \
} while(0)
我的问题是:是否可以编写单个 RETURN_IF_FALSE
宏来处理返回值的void
函数和函数?我坐下来尝试使用varargs宏进行某些操作,并很快发现我并不擅长编写复杂的宏。我开始使用这个测试程序:
#include <stdio.h>
#include <assert.h>
#define RETURN_IF_FALSE(cond, msg, ... ) \
do { \
if (!(cond)) { \
fprintf(stderr, "%s\n", (msg)); \
assert((cond)); \
} \
return (##__VA_ARGS__); \
} while(0)
int main()
{
RETURN_IF_FALSE(1 < 0, "1 is not less than 0!", -1);
return 0;
}
也许并不奇怪,它产生了以下编译错误:
g++ macro_test.cpp -o macro_test
macro_test.cpp:10:14: error: pasting "(" and "-" does not give a valid preprocessing token
return (##__VA_ARGS__); \
^
macro_test.cpp:16:5: note: in expansion of macro ‘RETURN_IF_FALSE’
RETURN_IF_FALSE(1 < 0, "1 is not less than 0!", -1);
^
甚至可能用一个宏来覆盖这两种情况吗?我在Linux上使用gcc 4.8.1。 (我可以使用-std=c++11
进行编译,如果它有帮助......)
更新:为了实现这个完整的圈子,我最终根据@Turix的回答和@Deduplicator提出的移动{{{ {1}}打电话以避免在阳光灿烂的日子里对条件进行双重评估。情况下:
assert()
(我认为,设置一个&#39;自由形式的消息字符串并不是真正的必要/有用,所以我只是从条件中生成一个罐装的......) / p>
答案 0 :(得分:2)
只需用return (##__VA_ARGS__);
替换宏return __VA_ARGS__ ;
的这一部分,我认为它应该做你想要的(假设你传递的返回值不是一个复杂的表达式 - 如果它是,你需要用括号预先包装参数。)
答案 1 :(得分:1)
我让这个工作。
#include <stdio.h>
#define RET_IF_FALSE(x, y, z) if (!x) { printf(y); return z; }
int a(int *p)
{
RET_IF_FALSE(p, __FUNCTION__, 0);
return *p;
}
void b(int *p)
{
RET_IF_FALSE(p, __FUNCTION__, );
}
int main()
{
int x;
x = a(&x);
b(&x);
x = a(NULL);
b(NULL);
return 0;
}
它可能不是带有逗号的最漂亮的解决方案,并且根据gcc的-pedantic选项不符合标准。
使用:
#define RET_IF_FALSE(x, y, ...) if (!x) { printf(y); return __VA_ARGS__; }
其余代码同样适用于gcc with pedantic和-std = c99,以及-cd = c ++ 11 in clang ++和g ++。不确定MS编译器做了什么,因为他们对标准的支持有时候不那么出色(我目前还没有Windows设置进行测试)。