当我用优化(选项-O1,-O2,-O3等)编译它时,我正在编写一个不起作用的C++程序(我遇到了分段错误),但是当我编译它时它工作得很好优化.
我的代码中是否有错误的可能性?或者我应该假设这是GCC中的错误?
我的GCC版本是3.4.6.
这种问题有没有已知的解决方法?
我的程序的优化和未优化版本之间的速度差异很大,所以我真的需要使用优化.
这是我原来的算子.没有优化级别的工作正常,并且在任何优化级别都会引发分段错误:
struct distanceToPointSort{ indexedDocument* point ; distanceToPointSort(indexedDocument* p): point(p) {} bool operator() (indexedDocument* p1,indexedDocument* p2){ return distance(point,p1) < distance(point,p2) ; } } ;
并且这个可以完美地适用于任何级别的优化:
struct distanceToPointSort{ indexedDocument* point ; distanceToPointSort(indexedDocument* p): point(p) {} bool operator() (indexedDocument* p1,indexedDocument* p2){ float d1=distance(point,p1) ; float d2=distance(point,p2) ; std::cout << "" ; //without this line, I get a segmentation fault anyways return d1 < d2 ; } } ;
不幸的是,这个问题难以重现,因为它发生了一些特定的值.我在对超过一千个向量中的一个进行排序时得到了分段错误,所以它实际上取决于每个向量具有的特定值组合.
现在您发布了代码片段并找到了工作解决方法(@Windows程序员的答案),我可以说也许您正在寻找的是-ffloat-store
.
-ffloat店
不要将浮点变量存储在寄存器中,并禁止可能改变浮点值是从寄存器还是内存中获取的其他选项.
这个选项可以防止诸如68000之类的机器上出现不希望的过度精度,其中浮动寄存器(68881)比双重应该具有更高的精度.同样适用于x86架构.对于大多数程序来说,多余的精度只会很好,但有些程序依赖于IEEE浮点的精确定义.在修改它们以将所有相关的中间计算存储到变量中之后,对这些程序使用-ffloat-store.
资料来源:http://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Optimize-Options.html
我会先假设你的代码错了.
虽然很难分辨.
您的代码是否编译为0警告?
g++ -Wall -Wextra -pedantic -ansi
这里有一些似乎有用的代码,直到你点击-O3 ...
#includeint main() { int i = 0, j = 1, k = 2; printf("%d %d %d\n", *(&j-1), *(&j), *(&j+1)); return 0; }
没有优化,我得到"2 1 0"; 有了优化,我得到了"40 1 2293680".为什么?因为我和k得到了优化!
但我正在取j的地址并走出分配给j的内存区域.标准不允许这样做.您的问题很可能是由与标准的类似偏差引起的.
我觉得valgrind在这些时候经常会有所帮助.
编辑:一些评论者认为标准允许任意指针算术.它不是.请记住,某些体系结构具有有趣的寻址方案,对齐可能很重要,如果溢出某些寄存器,则可能会出现问题!
关于向指针添加/从指针中减去一个整数的[草稿]标准的字样(强调添加):
"如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象的最后一个元素,则评估不会产生溢出; 否则,行为是未定义的. "
看到&j甚至没有指向数组对象,&j-1和&j + 1几乎不能指向同一个数组对象的一部分.因此,简单地评估&j + 1(更不用说解除引用它)是未定义的行为.
在x86上,我们可以非常自信地将一个添加到指针是相当安全的,只需将我们带到下一个内存位置即可.在上面的代码中,当我们对内存包含的内容做出假设时会出现问题,当然标准不会接近.
错误在您的代码中.根据C标准,你可能正在做一些调用未定义行为的东西,它恰好在没有优化的情况下工作,但是当GCC对执行其优化做出某些假设时,代码会在这些假设不正确时中断.确保使用该-Wall
选项进行编译,这-Wextra
可能也是一个好主意,看看是否有任何警告.您也可以尝试-ansi
或-pedantic
,但这些可能会导致误报.
作为一个实验,试着看看这是否会迫使编译器一致地舍入所有内容.
volatile float d1=distance(point,p1) ; volatile float d2=distance(point,p2) ; return d1 < d2 ;