繁体   English   中英

为什么这个被零除错误只出现在优化代码中?

[英]Why does this divide-by-zero error only occur in optimized code?

我刚刚发现了一个奇怪的错误,只有在打开优化时才会出现这个错误( g++ -O2 )。 interval设置为零(从命令行参数)时,以下代码中是Arithmetic exception

for(int i = 0; i < n; ++i) {
  if((i + 1) % interval == 0) { // exception here
    DoSomething();
  }
}

很明显,模零操作会抛出一个被零除的异常,但为什么只有在代码编译时才会启用优化?

除以零始终是未定义的行为。 使用不同的优化设置获得不同结果的事实仍然适合未定义行为的定义。

不断折叠。

你声明interval是一个全局的const int,编译器会把你的话告诉你。

您没有告诉我们'interval'的设置位置。 优化器可能正在执行将“interval”设置为0的操作。将代码更改为

for(int i = 0; i < n; ++i) {
  if (0==interval) { break; }
  if((i + 1) % interval == 0) { // exception here
    DoSomething();
  }
}

并看看你是否仍然得到错误。 或者更好的是,告诉我们'间隔'在哪里获得它的价值。

你能提供一个证明这个问题的例子吗? 如果优化更改结果,则需要反汇编代码并比较差异。 你的目标平台是什么? x86,arm,ppc? 操作系统? 等等?

#include 
const int interval=BOB;
int main ( void )
{
    int i,n;
    n=10;
    for(i = 0; i < n; ++i)
    {
        if((i + 1) % interval == 0)
        { // exception here
            printf("%d\n",i);
        }
    }
    return(0);
}
gcc interval.c -DBOB=0 -O2 -o interval
interval.c: In function ‘main’:
interval.c:15: warning: division by zero

编制者想通了......

编辑:

如果您尝试从命令行参数分配它,您应该得到编译器错误,因此无法执行任何操作。

#include <stdio.h>
const int interval;
int main ( int argc, char *argv[] )
{
    int i,n;
    if(argc<2) return(1);
    interval=atoi(argv[1]);

    n=10;
    for(i = 0; i < n; ++i)
    {
        if((i + 1) % interval == 0)
        { // exception here
            printf("%d\n",i);
        }
    }
    return(0);
}
gcc -o interval interval.c
interval.c: In function ‘main’:
interval.c:7: error: assignment of read-only variable ‘interval’

请提供一个完整的例子。

很有可能使用const并使编译器工作意味着变量从错误的地址被拉出并获得在那里发生的任何事情,这可能是也可能不是零,这取决于该地址是什么以及代码的所有其余部分。 更改优化设置会移动该地址的位置或指向的位置或执行期间更改的内容,直到更改结果为止。

编辑:

#include <stdio.h>
int main ( int argc, char *argv[] )
{
const int interval;
    int i,n;
    if(argc<2) return(1);
    interval=atoi(argv[1]);

    n=10;
    for(i = 0; i < n; ++i)
    {
        if((i + 1) % interval == 0)
        { // exception here
            printf("%d\n",i);
        }
    }
    return(0);
}
gcc -c interval.c 
interval.c: In function ‘main’:
interval.c:7: error: assignment of read-only variable ‘interval’

编译器仍然知道它是一个只读变量,使用地址指向非const变量,它不会改变其只读状态,只是摆脱了编译器错误,但从长远来看仍然失败。 正如设计的那样,例如.text被放置在只读存储器(rom / flash)中,那么无论你玩多少寻址和指针游戏,你都无法改变它的运行时间,直到你删除const并使它成为一个读/写变量。 这样的指针操作无论如何都是一个主要的罪,因为它可以并且最终会在你优化的时候失败(如果你使用一个非常好的编译器而不一定是gcc,虽然它也在gcc上也失败了)(99.999999999999%的时候它运气是否有效,但在失败时可以解释并指向软件设计而不是编译器或语言。 除非const是这个问题的根本原因,否则只需删除const并给我们一个演示问题的完整示例。 在一个下午或一天内,这可能会被关闭。

编辑2:

unsigned int fun  ( unsigned int a )
{
    const unsigned int b = 7;
    *(unsigned int *)&b = 5;
    return(a+b);
}

通过优化编译以上内容,您将得到:

.global fun
fun:
    add r0, r0, #7
    bx  lr

正如所料,const使b只读。 没有const:

unsigned int fun  ( unsigned int a )
{
    unsigned int b = 7;
    *(unsigned int *)&b = 5;
    return(a+b);
}
.global fun
fun:
    add r0, r0, #5
    bx  lr

我对此感到惊讶,但从未如此表明const是如何工作的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM