现在我写
assert(false);
在我的代码不应该到达的地方。一个非常C风格的例子是:
int findzero( int length, int * array ) {
for( int i = 0; i < length; i++ )
if( array[i] == 0 )
return i;
assert(false);
}
我的编译器认为,一旦达到assert(false),程序就结束了。但是,每当我出于性能原因使用-DNDEBUG进行编译时,最后一个Assert就会消失,编译器警告说,执行结束了函数,没有返回语句。
如果已经到达了一个被认为是无法到达的代码部分,有什么更好的替代方法来完成程序呢?
- 被编译器识别并且不产生警告(如上面的警告或其他警告)
- 甚至可能允许自定义错误消息。
我明确地对解决方案感兴趣,不管它是现代C++还是90年代的C。
9条答案
按热度按时间kuhbmx9i1#
替换你的
assert(false)
正是“不可达”内置函数的作用。它们在语义上等同于
assert(false)
的用法,事实上,VS 's的拼写非常相似。GCC/叮当声/英特尔:
MSVS:
无论
NDEBUG
(与assert
不同)或优化级别如何,这些都有效。你的编译器,特别是上面的内置编译器,也可能是
assert(false)
编译器,会点头表示你“承诺”函数的某一部分永远不会被执行。它可以利用这一点对特定的代码路径进行优化,并且它会关闭关于缺少返回的警告,因为你已经“承诺”这是故意的。这样做的代价是语句本身有未定义的行为(很像函数已经结束了)。在某些情况下,你可能会考虑抛出一个异常(或者返回一些“错误代码”值),或者调用
std::abort()
(在C中)来终止程序。有一个建议(P0627R0),将其作为标准属性添加到C中。
从the GCC docs on Builtins开始:
如果控制流到达
__builtin_unreachable
点,则程序未定义。这在编译器无法推断代码不可达的情况下很有用。[..]wf82jlnq2#
作为一种完全可移植的解决方案,请考虑以下内容:
当然,消息部分是可选的。
crcmnpdw3#
我喜欢用
...也可以带条件使用,如
这样做的好处是,如果Assert不成立,该字符串会显示在错误消息中。
pxyaymoc4#
我使用了一个自定义Assert,当
NDEBUG
打开时,它会变成__builtin_unreachable()
或*(char*)0=0
(我还使用了一个枚举变量而不是宏,以便可以轻松地为每个作用域设置NDEBUG)。在伪代码中,它类似于:
__builtin_unreachable()
应该消除警告,同时帮助优化,但在调试模式下,最好有一个assert或abort();
,这样您就可以获得可靠的死机。(__builtin_unreachable()
在达到时只会给您未定义的行为)。ylamdve65#
看起来std::unreachable()已经进入C++23:
https://en.cppreference.com/w/cpp/utility/unreachable
cczfrluj6#
我推荐C++ Core Gudelines的Expects和Ensures。它们可以被配置为中止(默认)、抛出或在违反时不做任何事情。
若要抑制编译器对不可达分支的警告,您也可以使用
GSL_ASSUME
。dsf9zpds7#
assert
是针对那些实际上不可能在执行过程中发生的情况。在调试中指出“嘿,原来你认为不可能的事情实际上并不是不可能的”是很有用的。看起来你 * 应该 * 在给定的例子中做的是表达函数的失败。可能是通过返回-1
,因为这不是一个有效的索引。在某些情况下,设置errno
来澄清错误的确切性质可能是有用的。然后,利用这个信息,调用函数可以决定如何处理这样的错误。根据此错误对应用程序其余部分的严重程度,您可以尝试从中恢复,或者只记录此错误并调用
exit
来解决它。zpjtge228#
我相信你得到这些错误的原因是因为Assert通常被用来调试你自己的代码。当这些函数在发行版中运行时,应该使用异常来代替std::abort()的退出来指示程序异常终止。
如果您仍然想使用Assert,PSkocik提供了一个关于定义自定义Assert的答案,这里还有一个链接,有人建议使用自定义Assert,以及如何在cmake here中启用它们。
8ftvxx2r9#
有时在样式指南中可以找到的一条规则是
“永远不要从函式中间传回”
所有函数都应该在函数的末尾有一个return。
遵循此规则,您的程式码看起来会像: