2017-05-30 55 views
2

我懷疑我發現了一個g ++優化錯誤,它涉及取消引用具有負索引的對象(結構體)中的數組。g ++ 4.8.5具有負數組索引的循環優化錯誤

在下文中,節點是結構,其具有陣列前述它(在我的實際代碼它是一個跳躍列表,其中它的兩個數的指針和其數據包的大小是可變的和未知的節點底層的SkipList代碼,因此決定將指針放在對象引用和數據包之前 - 在這個對象之後的這段時間很長)。

#include <iostream> 
#include <stdlib.h> 

class Node { 
public: 
    unsigned int ptr[1]; // really an array going backwards 
    long datum; // This seems to be necessary for the bug to surface                                  

}; 

class NodeList { 
public: 
    Node* hdr; 
    NodeList() { 
    void* p_v = malloc(sizeof(Node) + 32 * sizeof(unsigned int)); 
    hdr = (Node*)((char*)p_v + 32 * sizeof(unsigned int)); 
    hdr->ptr[-5]=100; 
    } 
    void setNodes() { 
    int nn=0; 
    while(rand() > 20 && nn<9) { 
     nn++; 
    } 
    if(nn < 9) { 
     nn = 9; 
    } 
    // It is a logical truth that nn = 9 here                                        
    //nn = 9; // IF THIS IS UNCOMMENTED EVERYTHING WORKS!                                     
    std::cout << "nn=" << nn << " (should be 9) " << std::endl; 
    int ctr = 0; 
    for(int i=0; i<=nn; i++) { 
     ctr++; 
     hdr->ptr[-i]=0; 
    } 
    std::cout << "ctr was incremented " << ctr << " times (should be 10) and hdr->ptr[-5] = " << hdr->ptr[-5] << " (should be 0)\n"; 
    } 
}; 

int main(int argc, char** argv) { 
    NodeList list; 
    list.setNodes(); 
} 

預期輸出具有CTR遞增10次,HDR-> PTR [-5]爲0優化代碼只是通過循環一次進入(即不循環),和葉ptr-> HDR [ - 5]爲100.這是一個錯誤。

-fno-aggressive-loop-optimizations似乎可以解決它,但顯然如果輸出代碼是正確的話會更好。

我把這裏放在這裏(a)得到驗證,這是一個錯誤,因爲我是一個新手,這是我的第一個問題,(b)詢問任何熟知gcc dev社區的人應該怎麼做它(例如,我應該如何報告它,以及它是否在後來的版本中得到修復),以及(c)允許在CentOS 7(或任何其他4.8版本的發行版)上經歷過這個最令人沮喪和耗時的問題的人,看到確認他們已經擊中了同胞患者的錯誤!

+0

對(C風格)數組不使用負指數是未定義的行爲? – nefas

+0

不,對於* all * n(正數和負數),'arr [n]'被定義爲'*(arr + n)'。當然,要確保參考是正確分配的內存。見[這個問題](https://stackoverflow.com/q/3473675/8084766) – galois99

+0

[這個問題](https://stackoverflow.com/questions/3473675/are-negative-array-indexes-allowed-in- c)可能有你想要的答案。 – nefas

回答

1

這裏必須小心「數組」的含義。數組是什麼定義爲

some_type arr[number]; 

而不是像

some_type*ptr = some_address; 

負指數並沒有什麼不同,以積極的索引和ptr[n]被解釋爲*(ptr+n)(你甚至可以在C使用n[ptr])。因此在索引時使用指針算術。

它是在C 未定義行爲(UB)和C++訪問陣列的邊界之外的元素,無論這是如何實現的。例如

some_type arr[10]; 
some_type*ptr = arr+5; 
some_type foo = ptr[-4]; // ok, access to arr[1] 
some_type bar = ptr[-6]; // UB, out-of-bound access 
some_type val = arr[-1]; // UB, out-of-bound access 
+0

怎麼樣'some_type var1;'聲明某處。然後某處之後的'some_type * var_p = &var1;'現在我的問題是是否引用說'var_p [1]'或'var_p [-1]'是UB?如果是的話,你會怎麼做參考之前無需調用UB對象的數組的把戲? – galois99

+0

@ galois99這與你原來的帖子完全不同,因爲沒有涉及數組。我不確定,但強烈建議不要這樣的事情,除非你非常清楚你在做什麼(你不這樣做,否則你不會問)。 – Walter