计算结果为零且可用作语句的函数宏
Posted
技术标签:
【中文标题】计算结果为零且可用作语句的函数宏【英文标题】:Function macro that evaluates to zero and can be used as a statement 【发布时间】:2012-04-17 11:52:37 【问题描述】:我们有一个函数宏#define FOO(arg) foo(arg)
和int foo(const char* bar);
。当 NDEBUG 被定义时,FOO 被定义为#define FOO(arg) 0
,然而这会导致许多编译器警告,因为在许多情况下 FOO 的返回值没有被使用。该解决方案应与 ANSI C 编译器一起使用并且不会导致警告。我试过了:
(void)0
: 不能赋值给变量
static int foo(const char* bar) return 0;
: 在某些模块中导致未使用的静态函数警告
static inline int foo(const char* bar) return 0;
:仅适用于 C99 编译器
感谢您的帮助!
编辑1:
它有点像跟踪宏,并在整个项目中使用。大多数情况下,它只是用作FOO("function x called");
之类的声明,但在少数情况下,我看到了if (FOO("condition a")) /* some more debug output */
。定义了 NDEBUG 并启用了优化后,FOO 应该不会留下任何东西。这不是我想出来的,但我必须收拾这个烂摊子:)。
edit2:我应该补充一点,对于 gcc 发布版本,使用了这些标志:-O3 -Wall -ansi
edit3:现在我选择__inline int dummy() return 0;
。 __inline 在 ansi 模式下与 VisualC 和 GCC 一起工作。
【问题讨论】:
你能举出更多例子来说明FOO()
在你的代码中是如何使用的吗?
你是否总是使用来自printf()
的返回值?
如果您不介意调用 foo() 并且只想确保使用的返回值为 0,您可以使用逗号运算符和 #define FOO(arg) (foo(arg), 0)
【参考方案1】:
我猜这有点依赖于编译器,但这应该可以工作:
#ifndef NDEBUG
#define FOO(arg) foo(arg)
#else
#define FOO(arg) ((int)0)
#endif
它防止“表达式无效”警告,它什么都不做,使用时它的值仍然是0。
已编辑 看起来它不是那么便携所以(现在)你有这些条件:
(0)
或 ((int)0)
至少在 VC 2010 上工作。
__noop
应该适用于 2003 年以后的任何版本的 VC。
VC6 不是问题,因为它根本不会发出 C4555 警告。对于您可以使用的其他编译器:
((void)0, 0)
它可能适用于很多编译器(也许它更便携?)。
inline int foo(const char* bar) return 0;
可与任何其他 C99 编译器一起使用(如您所写,您可能需要在 gcc 上将其声明为 static
)。
对于任何其他史前 C 编译器,请使用@Jobs 指出的解决方案:abs(0)
【讨论】:
有趣,我想知道为什么会这样...请注意,在 GCC 上,演员阵容甚至不是必需的。 我仍然收到 -Wall 警告 @maep 你在用VC吗?我正在使用 2k10 并且它没有给出任何警告(正如 Job 在大多数编译器中指出的那样,即使强制转换也是不必要的)。你会收到什么样的警告? 在 GCC 上你会得到warning: statement with no effect
。我刚刚注意到我首先错误地测试了您的示例:-)
@Adriano:我正在使用 gcc 4.4,但我们正在构建从 6.0(哎呀,我知道)、Intel、Sun 和其他一些 UNIX 版本开始的所有 VS 编译器。【参考方案2】:
您可以采取以下措施来防止警告:
#ifndef NDEBUG
#define FOO(arg) foo(arg)
#else
#define FOO(arg) abs(0)
#endif
我并不是说这很理想(例如,您必须确保在任何地方都包含stdlib.h
),但它确实可以防止警告。
【讨论】:
这可以工作,但正如你所说,它并不理想。我必须检查编译器是否会在发布版本中删除它。 @maep:是的,我也想过这个问题。但是,我希望任何体面的编译器都会在发布版本中删除它。顺便说一句,GCC 似乎即使在-O0
也将其删除。
一些编译器可能会警告调用纯函数而不使用返回值...
gcc 喜欢这个,但是 clang 会抱怨。【参考方案3】:
我会做一些依赖于 C 版本的事情。在头文件中:
#if __STDC_VERSION__ > 199900L
inline int foo(const char* bar) return 0;
#else
int foo(const char* bar);
#endif
在一个编译单元中
#if __STDC_VERSION__ < 199900L
int foo(const char* bar) return 0;
#else
int foo(const char* bar);
#endif
或者使用类似 Job's answer 的旧 C 版本,这是一个肯定会被优化但不会产生警告的函数。
【讨论】:
以上是关于计算结果为零且可用作语句的函数宏的主要内容,如果未能解决你的问题,请参考以下文章
只有 assignmentcallincrementdecrement 和 new 对象表达式可用作语句