我发现以下代码在调试版本中正常工作,但在版本中不正确:
enum FileFormatDetection
{
Binary,
ASCII,
Auto
};
FileFormatDetection detection_mode = (FileFormatDetection)ReadIntKey(NULL, KEY_ALL, "FIL_ASCIIORBINARY", -1); // Assigns -1, as confirmed by debug output
if (detection_mode < 0 || detection_mode > 2)
{
// Not a valid value, so set to default:
detection_mode = Auto;
}
Run Code Online (Sandbox Code Playgroud)
在每个构建中,调试输出确认该值为-1.在调试版本中,值-1导致输入if分支; 在发布中,它没有.
我已经尝试将detection_mode转换为int,如下所示:
if ((int)detection_mode < 0 || (int)detection_mode > 2)
Run Code Online (Sandbox Code Playgroud)
和:
if (int(detection_mode) < 0 || int(detection_mode) > 2)
Run Code Online (Sandbox Code Playgroud)
但没有任何区别.
我能做到这一点的唯一方法是将枚举变量转换为整数堆栈变量并测试:
int detection_int = (int)detection_mode;
if (detection_int < 0 || detection_int > 2)
{
...
Run Code Online (Sandbox Code Playgroud)
现在按预期输入if分支.
我无法理解为什么这是必要的 - 我仍然认为原始代码(或者至少测试演员临时代码)应该有效.任何人都可以解释为什么没有?
Dav*_*eas 10
问题是,当您为枚举中的枚举器之一分配一个值时,强制转换会导致未定义的行为.
在发布模式下编译时,优化器会看到以下表达式:
if (detection_mode < 0 || detection_mode > 2)
Run Code Online (Sandbox Code Playgroud)
并且知道detection_modeis 的类型FileFormatDetection,它知道该特定枚举的所有有效值都在范围内,因此if语句永远不会true(至少在一个定义良好的程序中)所以它if完全删除了.
铸造到int在if没有帮助的,因为推理的同一行仍然适用:价值投之前(也是一个定义良好的程序)的范围是[0..2]这样优化删除if.重要的是要注意,演员是否明确并不重要,因为枚举将被转换int为两种情况下的比较.
如果您将值存储在一个int然后所有更改.有许多int值超出该范围,因此必须进行比较.另请注意,通过此更改,程序将得到很好的定义,因为-1 它是有效的int.这实际上就是你应该做的事情:将值作为一个int,并且只有当它可以转换为枚举时,才能执行转换.
变量detection_mode具有类型FileFormatDetection,因此它只能(合法地)包含0..2范围内的值.其他任何东西都是未定义的行为.在你的情况下,显然,optmizer正在认识到这一点,并将测试抑制为小于零.
你应该做的是阅读一个int,并且只在范围检查FileFormatDetection 后转换到
:
int raw_detection_mode = ReadIntKey(...);
if ( raw_detection_mode <= 0 || raw_detection_mode > 2 ) {
raw_detection_mode = Auto;
}
FileFormatDetection detection_mode =
static_cast<FileFormatDetection>( raw_detection_mode );
Run Code Online (Sandbox Code Playgroud)