3

我刚刚发现了一个奇怪的错误,它仅在打开优化时才发生(g++ -O2)。它是Arithmetic exception以下代码中的一个,当interval被设置为零时(来自命令行参数):

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

很明显,模零运算抛出了一个被零除的异常,但是为什么只有在打开优化编译代码时才会出现这种情况?

4

4 回答 4

13

除以零总是未定义的行为。您使用不同的优化设置得到不同的结果这一事实仍然符合未定义行为的定义。

于 2010-10-04T01:51:09.033 回答
1

不断折叠。

您将 interval 声明为全局 const int 并且编译器接受了您的话。

于 2010-10-04T02:14:04.267 回答
0

你能提供一个例子来说明这个问题吗?如果优化改变了结果,那么您需要反汇编代码并比较差异。你的目标平台是什么?x86,手臂,ppc?操作系统?ETC?

#包括
常量 int 间隔=BOB;
int main ( 无效 )
{
    诠释我,n;
    n=10;
    for(i = 0; i < n; ++i)
    {
        if((i + 1) % 区间 == 0)
        { // 这里例外
            printf("%d\n",i);
        }
    }
    返回(0);
}
gcc 间隔.c -DBOB=0 -O2 -o 间隔
interval.c:在函数'main'中:
interval.c:15:警告:除以零

编译器想通了...

编辑:

如果您尝试从命令行参数分配它,您应该得到一个编译器错误,因为没有任何东西可以执行。

#include <stdio.h>
const int 间隔;
int main (int argc, char *argv[])
{
    诠释我,n;
    如果(argc<2)返回(1);
    间隔=atoi(argv[1]);

    n=10;
    for(i = 0; i < n; ++i)
    {
        if((i + 1) % 区间 == 0)
        { // 这里例外
            printf("%d\n",i);
        }
    }
    返回(0);
}
gcc -o 间隔interval.c
interval.c:在函数'main'中:
interval.c:7: 错误:只读变量'interval'的赋值

请提供一个完整的例子。

很有可能使用 const 并让编译器工作意味着该变量是从错误的地址中提取出来的,并且根据该地址是什么以及您的所有其余代码,可能会或可能不会为零。 . 更改优化设置会移动该地址所在的位置或它指向的位置或在执行期间更改为的位置,直到更改结果为止。

编辑:

#include <stdio.h>
int main (int argc, char *argv[])
{
const int 间隔;
    诠释我,n;
    如果(argc<2)返回(1);
    间隔=atoi(argv[1]);

    n=10;
    for(i = 0; i < n; ++i)
    {
        if((i + 1) % 区间 == 0)
        { // 这里例外
            printf("%d\n",i);
        }
    }
    返回(0);
}

gcc -c 间隔.c
interval.c:在函数'main'中:
interval.c:7: 错误:只读变量'interval'的赋值

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

编辑2:

unsigned int fun ( unsigned int a )
{
    常量无符号整数 b = 7;
    *(无符号整数 *)&b = 5;
    返回(a+b);
}

用优化编译上面的代码,你会得到:

    .global 乐趣
乐趣:
    添加 r0, r0, #7
    bx lr

正如预期的那样, const 使 b 只读。没有常量:

unsigned int fun ( unsigned int a )
{
    无符号整数 b = 7;
    *(无符号整数 *)&b = 5;
    返回(a+b);
}
    .global 乐趣
乐趣:
    添加 r0, r0, #5
    bx lr

我对此感到惊讶,但从未如此少地展示了 const 的工作原理。

于 2010-10-04T05:24:23.693 回答
0

您没有向我们展示“间隔”的设置位置。优化器可能正在执行将“间隔”设置为 0 的操作。将代码更改为

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

看看你是否仍然得到错误。或者更好的是,向我们展示“间隔”的价值所在。

于 2010-10-04T01:58:08.337 回答