簡體   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