我正在编译一些没有优化的代码,但是在启用优化的情况下中断了。我怀疑代码的某些关键部分被优化了,导致逻辑崩溃。
我想做类似的事情:
code...
#disable opt
more code...
#enable opt
如果我可以设置该部分的优化级别(如O0,O1 ......)
,那就更好了对于那些暗示它是代码的人:
要删除的代码部分(通过反汇编目标文件进行检查):
void wait(uint32_t time)
{
while (time > 0) {
time--;
}
}
我严重怀疑该代码存在问题
答案 0 :(得分:5)
如果优化导致您的程序崩溃,那么您有一个错误,应该修复它。通过不优化这部分代码来隐藏问题是一种糟糕的做法,会使代码变得脆弱,而且就像为下一个支持代码的开发人员留下地雷一样。更糟糕的是,忽略它,你将无法学习如何调试这些问题。
一些可能的根本原因:
正在优化的硬件访问次数:使用Volatile 关键代码不太可能被优化,但如果您正在触摸硬件寄存器,则应添加volatile属性以强制编译器访问这些寄存器,而不管优化设置如何。
竞争条件:使用Mutex or Semaphore来控制对共享数据的访问 您更有可能具有特定时间的竞争条件,并且优化会导致此时间条件显示出来。这是一件好事,因为这意味着你可以解决它。您是否有多个线程或进程访问相同的硬件或共享数据?您可能需要添加互斥锁或信号量来控制访问以避免计时问题。
Heisenbug:这是代码行为根据是否添加调试语句或代码是否已优化而发生变化的时间。有一个很好的例子here,其中优化的代码以高精度在寄存器中进行浮点比较,但是当添加printf时,则将值存储为双精度数并与精度较低进行比较。这导致代码单向失败,而另一方失败。也许这会给你一些想法。
定时循环得到优化:创建一个等待函数,该函数通过创建一个递增局部变量以增加延迟的定时循环来工作,这不是一种好的编程风格。可以基于编译器和优化设置完全优化这样的循环。此外,如果您移动到其他处理器,延迟量将会改变。延迟功能应该基于CPU滴答或实时工作,这不会得到优化。延迟功能使用CPU时钟或实时时钟,或调用标准功能,如nanosleep()或use a select with a timeout。请注意,如果您使用的是CPU滴答,请务必对该功能进行评论,并强调该实现需要针对特定目标。
底线:正如其他人所建议的那样,将可疑代码放在一个单独的文件中并编译该单个源文件而不进行优化。测试它以确保它正常工作,然后将一半代码迁移回原始代码,并重新测试一半代码优化而不是一半代码,以确定您的错误位置。一旦你知道哪一半有Heisenbug,使用分而治之来重复这个过程,直到你找到优化后失败的最小代码部分。
如果你能在那时找到错误,那很好。否则在这里发布该片段,以便我们可以帮助调试它。提供编译器optmization标志,用于在优化时使其失败。
答案 1 :(得分:2)
您可以浏览GCC文档。例如:
Function specific option pragmas
#pragma GCC optimize ("string"...)
此pragma允许您为稍后在源文件中定义的函数设置全局优化选项。可以指定一个或多个字符串。在此点之后定义的每个函数都就像为该函数指定了
attribute((optimize("STRING")))
一样。选项周围的括号是可选的。有关optimize属性和属性语法的详细信息,请参阅函数属性。
另请参阅push_options
,pop_options
和reset_options
的编译指示。
optimize
optimize属性用于指定使用与命令行中指定的不同优化选项编译函数。参数可以是数字或字符串。假设数字是优化级别。假定以O
开头的字符串是优化选项,而假设其他选项与-f
前缀一起使用。您还可以使用“#pragma GCC optimize
”编译指示来设置影响多个函数的优化选项。有关“#pragma GCC optimize
”编译指示的详细信息,请参阅功能特定选项编译指示。此属性仅用于调试目的。它不适用于生产代码。
此页面列出了许多优化选项,可以在命令行中使用-f
选项,因此使用optimize
属性和/或编译指示。
答案 2 :(得分:1)
您可以做的最好的事情是将您不希望优化的代码移动到单独的源文件中。在没有优化的情况下编译它,并将其与其余代码链接。
使用GCC,您还可以使用__attribute__((optimize("O0"))
声明一个函数来禁止优化。