我怀疑我发现了一个g ++优化错误,它与使用负索引的对象(结构)中的解引用数组有关。
在下面,Node是一个结构,它有一个前面的数组(在我的实际代码中,它是一个Skip List的节点,其中指针的数量和数据包的大小都是底层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-&gt; hdr [-5]这是一个错误。
-fno-aggressive-loop-optimizations似乎可以修复它,但如果输出代码是正确的,那么显然会更好。
我把这个放在这里(a)验证这是一个错误,因为我是这里的新手,这是我的第一个问题,(b)问一下在gcc开发社区知识渊博的人应该做些什么(例如,我应该如何报告,以及是否已在以后的版本中修复),以及(c)允许在CentOS 7(或任何其他版本4.8)上遇到过这个最令人沮丧和耗时的问题的人看到确认他们已经遇到了一位患者的错误!
答案 0 :(得分:1)
关于'array'的含义,必须注意这里。数组是任何定义为
的数组some_type arr[number];
但不是
some_type*ptr = some_address;
负指数与正指数没有差异,ptr[n]
被解释为*(ptr+n)
(您甚至可以在C中使用n[ptr]
。因此,在索引时,使用指针算法。
在C和C ++中未定义的行为(UB)来访问数组边界之外的元素,无论如何实现。例如
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