|
国外编译器设计大佬的讨论。
英文原文:
Well, the pedantic statement about optimization is:
If your program has a defined behavior according to the C standard and avoids any undefined or unspecified behavior and works as intended with no optimization, then it will also have the same behavior with full optimization and just be smaller and/or faster.
However, programmers make lots of mistakes and often use code constructs, which already are deeply in the area of undefined behavior. However, that code often works just by coincidence if the compiler is not optimizing too much. Some typical errors are:
exchanging data between interrupts or rtos tasks or exceptions with main code without the use of volatile (or memory barriers)
bad type casting with pointers
undefined use of memory
pointer to stack memory after return from function
pointer to malloc-ed memory, which is already free-d
use of memory with uninitialized or corrupted pointers
array overflow/underflow
use of uninitialized variables
bad assumptions, that in certain code sections no interrupts will happen
bad assumptions about "this variable is changed before that variable", and you expect this to be also true when looking at it from another context (interrrupt / exception / rtos task / main code)
Without optimization or low optimization levels, it happens surprisingly often, that these common errors have no bad consequence.
However, the whole specification of C is based on the assumption that the compiler can produce a heavily optimized result. The specification defines a term what is called "observable behavior". Basically "observable behavior" are just (read or write) accesses to volatile or I/O functions through the standard libraries. This is also why also all the processor special function registers (including those for the pins) are defined as volatile. And the specification then defines, that when you theoretically execute your program line by line on an abstract machine and you record a certain sequence of observable behaviors, and the real assembled program on the real device just has to reproduce this same sequence of observable behaviors. Between those observable, it can do everything it wants. In particular it can remove any code which is not relevant for producing that sequence of observable behaviors or replace it with more efficient code.
Furthermore, the compiler is allowed to assume, that its code is executed uninterrupted. So, it does not have to expect any interrupt, any exception or any rtos task switch or some hardware in the background which is changing the content of some memory. If there is such a thing, then it is your responsibility to tell the compiler about every possible effect, which such an interruption of the regular code execution might have or which the hardware in the background has, by declaring the possible affected things volatile.
I would recommend: Develop your code always with the highest optimization levels, which is the exact same optimization setting which you are going to release. Only if you have a serious problem, which you need to debug, then go temporary down to a lower setting like -Og or -O1 or -O0, and try to find out what is wring. But don't forget to go back to the high setting afterwards.
中文译文:
好吧,关于优化的迂腐陈述是:
如果您的程序根据C标准定义了行为,避免了任何未定义或未指定的行为,并且在没有优化的情况下按预期工作,那么它也会在完全优化时具有相同的行为,并且只是更小和/或更快。
然而,程序员犯了很多错误,并经常使用代码结构,这些代码结构已经深深地处于未定义的行为领域。然而,如果编译器没有进行太多优化,该代码通常只是巧合。一些典型的错误是:
在中断或rto任务之间交换数据,或使用主代码的例外,而不使用易失性(或内存障碍)
带有指针的不良类型铸造
未定义的内存使用
从函数返回后堆栈内存的指针
指向malloc-ed内存的指针,它已经是free-d
使用未初始化或损坏指针的内存
数组溢出/溢出
使用未初始化的变量
糟糕的假设,在某些代码部分中不会发生中断
关于“此变量在该变量之前更改”的错误假设,您预计从其他上下文(中断/异常/rtos任务/主代码)查看时也是如此
如果没有优化或低优化水平,这些常见错误不会产生不良后果,这出人意料地发生。
然而,C的整个规范是基于编译器可以产生高度优化结果的假设。该规范定义了一个术语,即所谓的“可观察行为”。基本上,“可观察行为”只是通过标准库(读写)访问volatable或I/O函数。这也是为什么所有处理器特殊功能寄存器(包括引脚的寄存器)都被定义为易失性。然后,规范定义了,当您在抽象机器上逐行执行程序时,您记录了一定的可观察行为序列,而真实设备上的真实组装程序只需重现同一顺序的可观察行为。在那些可观察到的人之间,它可以做它想做的一切。特别是,它可以删除任何与产生该可观察行为序列无关的代码,或用更有效的代码替换它。
此外,允许编译器假设其代码是不间断地执行的。因此,它不必期望任何中断、任何异常或任何rtos任务开关或后台正在更改某些内存内容的硬件。如果有这样的事情,那么您有责任通过声明可能受影响的东西是易失的,告诉编译器所有可能的影响,这种常规代码执行的中断可能会产生什么,或者后台的硬件会有什么影响。
我建议:始终以最高的优化级别开发您的代码,这与您将发布的优化设置完全相同。只有当您遇到严重问题时,您需要进行调试,然后暂时下到较低的设置,如-Og或-O1或-O0,并尝试找出什么是拨。但别忘了事后回到高处。
|
评分
-
查看全部评分
|