【发布时间】:2011-10-17 06:51:42
【问题描述】:
根据 C++ 标准 (5/5) 除以零是未定义的行为。现在考虑这段代码(有很多无用的语句来防止编译器优化代码):
int main()
{
char buffer[1] = {};
int len = strlen( buffer );
if( len / 0 ) {
rand();
}
}
Visual C++ 像这样编译if-statement:
sub eax,edx
cdq
xor ecx,ecx
idiv eax,ecx
test eax,eax
je wmain+2Ah (40102Ah)
call rand
很明显,编译器看到代码要除以零——它使用xor x,x 模式将ecx 清零,然后在整数除法中为第二个操作数提供服务。此代码在运行时肯定会触发“整数除以零”错误。
IMO 此类情况(当编译器知道代码将始终除以零时)值得出现编译时错误 - 标准并不禁止这种情况。这将有助于在编译时而不是在运行时诊断此类情况。
然而,我与其他几位开发人员交谈,他们似乎不同意 - 他们的反对意见是“如果作者想除以零来... emm... 测试错误处理怎么办?”
在没有编译器意识的情况下故意除以零并不难 - 使用 __declspec(noinline) Visual C++ 特定函数装饰器:
__declspec(noinline)
void divide( int what, int byWhat )
{
if( what/byWhat ) {
rand();
}
}
void divideByZero()
{
divide( 0, 0 );
}
它更具可读性和可维护性。当他“需要测试错误处理”并且在所有其他情况下都有很好的编译时错误时,可以使用该功能。
我错过了什么吗?是否有必要允许发射编译器知道除以零的代码?
【问题讨论】:
-
我假设您的问题仅适用于基本类型。我说的对吗?
-
@R. Martinho Fernandes:是的,让我们认为它仅限于基本类型。
-
我看到的问题是,实际上只有少数错误会在编译时被捕获,其余的是真正的运行时错误。我认为没有另一类具有这种二元性的错误。这有点奇怪。
-
另外我希望有一个警告,以便可以根据向后可比性/测试等的需要打开/关闭它
-
我不相信编译器会因为存在未定义的行为而拒绝一个格式良好的程序,但显然它可以。 1.3,在未定义行为的定义下:“允许的未定义行为范围从......到终止翻译......(发布诊断消息)。”它在注释中而不是适当的规则中,但对我来说已经足够了。但是,我仍然不希望看到编译器对这个特定选项过于激进。
标签: c++ visual-c++ compiler-construction divide-by-zero