有人知道如何获取此类数据吗?可以使用gcc bugzilla页面生成有关编译器漏洞与优化级别的统计信息吗?是否可能获取到无偏倚的数据呢?
您正在假设编译器在没有优化的情况下是无缺陷的,只有优化才是危险的。然而,编译器本身是程序,很常见地会存在各种缺陷,无论是否使用某些功能。当然,这些功能可能会使编译器更好或更差。
另一篇回答中提到了LLVM,LLVM存在一个众所周知的优化缺陷,他们似乎对修复此问题没有任何兴趣。
while(1) continue;
"gets optimized out, just goes away...sometimes...and other similar but not completely infinite loops also disappear in the llvm optimizer. Leaving you with a binary that doesnt match your source code. This is one I know there are probably many more in both gcc and llvm's compilers."
"gets optimized out"指的是在优化器中被优化掉了, 有时会出现其他类似但不完全无限循环的情况也会在LLVM优化器中消失。这会留下一个与您的源代码不匹配的二进制文件。我知道在gcc和llvm编译器中可能有更多类似的情况。
"gcc is a monster that is barely held together with duct tape and bailing wire. It is like watching one of those faces of death movies or something like that once you have had those images in your head one time, you cant unwatch them, they are burned in there for life. So it is worth finding out for yourself how scary gcc is, by looking behind the curtain. But you might not be able to forget what you had seen. For various targets -O0 -O1 -O2 -O3 can and have all failed miserably with some code at some point in time. Likewise the fix sometime is to optimize more not less."
"gcc是一个几乎只能依靠胶带和铁丝钳勉强维持的怪物。它就像看那种死亡面孔电影或者类似的东西,一旦你在脑海中有了那些图像,你就无法忘记,它们会在你的脑海中烙印下来一辈子。因此,值得自己去了解一下gcc的恐怖之处,看看幕后的情况。但是也许您看到的东西无法从头脑中抹去。对于各种目标,“-O0”、“-O1”、“-O2”和“-O3”都可能在某个时间点上惨败于某些代码。同样,有时修复的方法是进行更多而不是更少的优化。"
"When you write a program the hope is the compiler does what it says it does, just like you hope your program does what you say it does. But it is not always the case, your debugging does not end when the source code is perfect, it ends when the binary is perfect, and that includes whatever binary and operating system you hope to target (different minor versions of gcc make different binaries, different linux targets react differently to programs)."
"编写程序时,希望编译器能够做到其所说的那样,就像您希望您的程序按照您的意思执行一样。但这并不总是成立,您的调试不会在源代码完美时结束,它将在二进制文件完美时结束,包括您希望针对的任何二进制文件和操作系统(不同版本的gcc会生成不同的二进制文件,不同的Linux目标对程序有不同的反应)。
"The most important advise is develop and test using the target optimization level. if you develop and test by always building for a debugger, well you have a created a program that works in a debugger, you get to start over when you want to make it work somewhere else. gcc's -O3 does work often but folks are afraid of it and it doesnt get enough usage to be debugged properly, so it is not as reliable. -O2 and no optimization -O0 get a lot of mileage, lots of bug reports, lots of fixes, choose one of those or as another answer said, go with what Linux uses. Or go with what firefox uses or go with what chrome uses."
"最重要的建议是使用目标优化级别开发和测试。如果您始终为调试器构建程序进行开发和测试,那么您已经创建了一个只能在调试器中工作的程序,当您想将其在其他地方运行时,就必须重新开始。gcc的
优化器确实会增加您的风险。假设编译器使用50%的代码来获得没有优化的输出,再使用10%的代码来获取-O1,则您的风险增加了,使用更多的编译器代码,出现错误的风险更大,并且输出结果可能更差。为了达到-O2和-O3,需要使用更多的代码。减少优化并不能完全消除风险,但可以降低出错的概率。
void foo(void) { long long exp=3; while(!FermatCounterexampleExistsWithExponent(exp) exp++; someGlobal = exp;}
,还有另一个调用了 foo()
的函数并且做了一些其他的事情。如果 Fermat...
方法没有副作用,编译器可以自由地将一个单独的线程分离出来处理 foo
,只要它确保主线程在下一次访问 someGlobal
之前等待辅助线程完成。如果程序要做的所有有用的事情都可以在不实际访问 someGlobal
的情况下完成... - supercatbreak
、不访问任何易失性变量、不写入任何指针且无法修改循环条件的while
循环时发出警告,但我对规范说即使时间无限也不应被视为“副作用”并不反感。 - supercat我没有任何数据(也没有听说过任何人有数据...),但是...
在选择禁用优化之前,我会选择要使用的编译器。换句话说,我不会使用我不能信任其优化的任何编译器。
Linux内核是使用 -Os 编译的。这比任何 bugzilla 分析对我更有说服力。
就个人而言,我会接受 Linux 所适用的 gcc 的任何版本。
另一个参考数据是,苹果一直在从 gcc 转向 llvm,有时使用 clang 有时不使用。llvm 在某些 C++ 方面存在问题,虽然 llvm-gcc 现在好多了,但似乎 clang++ 仍然存在一些问题。但这证明了一种模式:虽然据称 Apple 现在使用 clang 编译 OS X 和 iOS,但他们几乎不使用 C++ 和 Objective-C++。因此,对于纯 C 和 Objective-C,我会信任 clang,但我仍然不相信 clang++。
我不知道gcc的bug,但C编程语言与当前硬件不相符。请记住,它是在20世纪70年代设计的,当时甚至还不清楚2的补码算术是否会成为未来的趋势。好吧,在C中添加2个无符号整数。规范说明您不允许溢出。编译器可以假定在添加后清除进位标志,并基于此进行进一步的优化。您假设使用2的补码算术(这些天谁不会呢),然后嘭,您刚刚设置了进位标志。像这样的事情是安全问题的主要来源。我认为即使是低级别的代码,Java也可能更好,因为它定义得更好,而当前的HotSpot即时编译器生成的代码运行速度与C一样快。您还可以查看D编程语言,很可能它也被定义得很好。
关于编译器优化器错误的最新研究https://www.sciencedirect.com/science/article/abs/pii/S0164121220302740
是的,编译器也会出现错误,而优化器可能会给您的代码添加错误;-(
一个无用的解决方案是使用多个优化选项进行编译和测试,并比较程序结果。
随着程序规模和复杂性的增加,运行足够的测试以确保编译器不会使您的代码变得更加错误变得不可行。
可以进行风险评估,我是否正在处理性能至关重要的小型项目?还是我正在处理内核或其他关键应用程序?如果是前者,则您可能对编译器提供的所有优化感到满意。如果是后者,建议从“-O0”开始,然后是“-O1”,然后...测量代码的关键性能指标。您可能会发现,“-O2”及以上提供的好处微不足道,不值得冒险。