【问题标题】:How to avoid getting "constant expression" on if's?如何避免在 if 上获得“常量表达式”?
【发布时间】:2013-07-02 22:27:29
【问题描述】:

我有一个assert 宏,可以解析为if,如下所示:

#define assert(expr) \
if (!(expr)) \
{ \
    handle_failed_assert(); \
}

忽略handle_failed_assert() 的工作原理,您无需引用do { ... } while(0) 技巧。请关注这背后的功能。

现在,真正的问题来了。有时我想强迫和断言,让它有意义。所以我们使用这个:

assert(!"Assert cause carefully described.");

问题是我们有这个基于 RVCT 2.2 的编译器 vrxcc,它在编译时会抛出以下警告:

#236-D: controlling expression is constant

当然,这会解析为编译常量if

我怎样才能欺骗编译器接受它?

【问题讨论】:

  • 我不知道这是否有助于警告,但我会使用 ?: 运算符而不是 if 语句,这样您就不必担心宏的扩展作为复合语句。它可以只是一个表达式。您也可以使用&&|| 代替?:,这些可能会使警告静音。
  • 我喜欢这样。像if (expr && handle_failed_assert()) 这样的东西可能会起作用。我会尝试报告。

标签: c if-statement assert assertions constant-expression


【解决方案1】:

您的问题最终归结为“我的编译器太聪明了,我如何让它停止抱怨某些事情,是的,是真的并且通常是程序员的错误,但在这种情况下 不是 一个程序员的错误”。只有两种方法可以做到这一点:

  • 智胜编译器。这取决于编译器。
  • 告诉编译器“不要抱怨,这不是错误。”这取决于编译器。

我对 vrxcc 一无所知。 R 的评论倾向于做第一个。这种事情几乎可以保证有效:

extern int __truefunc(void);
#define assert(expr) ((__truefunc() && (expr)) || __assert_fail(#expr))

其中truefunc 是一个始终返回 1 的函数,您可以单独编译以智取编译器。当然,代价是该死的无用运行时调用。

“告诉编译器”方法更好,但需要某种编译器文档协助。


附录:我在淋浴时突然想到,在你的特殊情况下,你已经决定恐慌,所以你可以有一个 panic 函数,并在这里调用它。缺点是您必须更改所有现有的 common_assert(!"some string") 调用,但至少您可以机械地这样做。

如果该语言有两个参数 assert 内置或作为标准的东西可能会很好。 FreeBSD 内核现在为此使用KASSERT,或多或少:

#define KASSERT(expr, panic_args) \
    do { if (!(expr)) panic panic_args; } while (0)

这在语法上有点笨拙,但非常灵活:

KASSERT(foo.field == FOO_MAGIC,
    ("memory overwrite of foo data structure: %d != %d",
        foo.field, FOO_MAGIC));

【讨论】:

  • 那么,真的有必要将__truefunc() 设为外部函数吗?我正准备使用 volatile 整数提出类似的建议。
  • @Spidey 另外,我必须强烈建议您将宏命名为 assert() 以外的名称,除非是为了避免严重混淆阅读您的代码的任何人。名为assert() 的宏是,如果你#include <assert.h>,由C 标准定义,如果条件为假,则调用abort()。如果您正在编写一个实际处理错误的断言类型宏(或函数),assert() 是一个错误的名称选择。
  • 其实是common_assert,别担心。
  • @ElchononEdelson:不一定; extern volatile 也可能起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-11-28
  • 2020-04-23
  • 1970-01-01
  • 2017-04-16
  • 1970-01-01
  • 2015-02-11
  • 1970-01-01
相关资源
最近更新 更多