在我的代码中,我习惯于编写包含如下断言的回退默认情况,以防止我忘记在语义发生变化时更新开关
switch(mode) {
case ModeA: ... ;
case ModeB: ... ;
case .. /* many of them ... */
default: {
assert(0 && "Unknown mode!");
return ADummyValue();
}
};
现在我想知道人工回退检查默认情况是否会干扰跳转表几代人?想象一下“ModeA”和“ModeB”等是连续的,因此编译器可以优化为一个表。由于“默认”情况包含实际的“返回”语句(因为断言将在发布模式下消失,并且编译器将抱怨缺少返回语句),因此编译器似乎不太可能优化默认分支。
处理这个问题的最佳方法是什么?一些朋友建议我用空指针取消引用替换“ADummyValue”,以便编译器在存在未定义行为时可以省略对缺少 return 语句的警告。有更好的方法来解决这个问题吗?
In my code I'm used to write fall-back default cases containing asserts like the following, to guard me against forgetting to update the switch in case semantics change
switch(mode) {
case ModeA: ... ;
case ModeB: ... ;
case .. /* many of them ... */
default: {
assert(0 && "Unknown mode!");
return ADummyValue();
}
};
Now I wonder whether the artificial fall-back check default case will interfere with jump table generations? Imagine "ModeA" an "ModeB" etc are consecutive so the compiler could optimize into a table. Since the "default" case contains an actual "return" statement (since the assert will disappear in release mode and the compiler will moan about a missing return statement), it seems unlikely the compiler optimizes the default branch away.
What's the best way to handle this? Some friend recommended me to replace "ADummyValue" with a null pointer dereference, so that the compiler, in presence of undefined behavior, could omit to warn about a missing return statement. Are there better ways to solve this?
发布评论
评论(7)
使用编译器扩展:
-
Use compiler extensions:
-
如果您的编译器是 MSVC,则可以使用 __assume 内在函数:http://msdn.microsoft.com/en-us/library/1b3fsfxw(v=VS.80).aspx
If your compiler is MSVC, you can use
__assume
intrinsic : http://msdn.microsoft.com/en-us/library/1b3fsfxw(v=VS.80).aspx至少对于我看过的编译器来说,答案通常是否定的。他们中的大多数人都会将这样的 switch 语句编译为大致相当于以下内容的代码:
At least with the compilers I've looked at, the answer is generally no. Most of them will compile a switch statement like this to code roughly equivalent to:
如果您使用“默认”(哈!)
,则该定义无论如何都与 NDEBUG 宏相关联,所以也许只是if you're using "default" (ha!)
<assert.h>
, the definition's tied to the NDEBUG macro anyway, so maybe just我只看到 1 个解决方案,以防优化实际上受到干扰:在默认情况下臭名昭著的“#ifndef NDEBUG”。这不是最好的技巧,但在这种情况下很清楚。
顺便说一句:您是否已经了解过编译器在有默认情况下和没有默认情况下会做什么?
I only see 1 solution in case the optimization actually is disturbed: the infamous "#ifndef NDEBUG" round the default case. Not the nicest trick, but clear in this situation.
BTW: did you already have a look what your compiler does with and without the default case?
如果你有一个永远不应该达到的状态,那么你应该杀死该程序,因为它刚刚达到了一个意想不到的状态,即使在发布模式下也是如此(你可能只是更外交,实际上保存用户数据并做所有其他好的事情下山之前)。
并且请不要沉迷于微观优化,除非您实际上已经测量(使用分析器)您需要它们。
If you have a state that should never be reached, then you should kill the program, because it just reached an unexpected state, even in the release mode (you might just be more diplomatic and actually save users data and do all that other nice stuff before going down).
And please don't obsess over micro optimizations unless you actually have measured (using a profiler) that you need them.
处理此问题的最佳方法是不要禁用断言。这样您还可以密切关注可能的错误。有时,应用程序崩溃时最好给出一条说明到底发生了什么的消息,然后继续工作。
The best way to handle this is not to disable the assert. That way you can also keep an eye on possible bugs. Sometimes it is better for the application to crash with a good message explaining what exactly happened, then to continue working.