计算结果为零且可用作语句的函数宏

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 对象表达式可用作语句

SAS 函数

让 printf 语句在 openCL 内核代码中工作

linux C语言 宏函数展开测试(复合语句表达式 ({}))

如果语句'参数的长度为零'则出现R错误[重复]

在C#三元运算符给出错误:只有赋值,调用,递增,递减和新对象表达式可用作语句