2017-05-30 56 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