【问题标题】:How to force GCC compiler to calculate constant values at compile time?如何强制 GCC 编译器在编译时计算常量值?
【发布时间】:2015-08-12 09:37:29
【问题描述】:

我有以下代码(CPU Atmel AVR ATmega64A):

#define UO_ADC1023  265
#define UREF_180V   (1023*180/UO_ADC1023)
....
if(ADC > UREF180) {do_something();}

这应该将 UREF_180V 评估为 694.87...,并且应该将此值四舍五入(更好)到 695 或向下(较差)到 694,以便与 ADC 寄存器进行比较。

但是我在编译时有integer overflow 警告。据此,我认为编译器生成的代码会在运行时计算 (1023*180/UO_ADC1023),这对我来说非常糟糕。

我想避免自己计算这些常量(#define UREF_180V 695 在这种情况下我可以确定它们确实是文字)以使代码更加灵活和可读。我还希望能够在编译器之后检查这些值。

所以问题是:

  1. 是否有可能强制 GCC 编译器在编译时计算这些常量?

  2. 如何检查这个计算值?

【问题讨论】:

  • 你的编译器链支持 C++11 吗?
  • @weltensturm,我不确定 :( 编译器设置截图:goo.gl/glQjfd

标签: gcc compilation macros constants avr


【解决方案1】:

AVR 上的int 是 16 位的。告诉编译器改用long(因为 1023 * 180 会溢出)。

#define UREF_180V   (1023L * 180 / UO_ADC1023)

【讨论】:

  • 谢谢!这很有用,但据我了解,这不是编译时间计算的保证?
  • 我不认为有任何实际的方法可以修改 GCC 的行为;如果可以,它总是在编译时计算值。
【解决方案2】:

宏被插入到调用的地方,之后可以编译它们的内容。

在 C++11 中,您可以在编译时使用 constexpr 计算表达式,如下所示:

constexpr auto UREF_180V = 1023*180/UO_ADC1023;

由于所有数字均为ints,因此结果为694。要正确舍入它,您必须将其中一个值更改为浮点数并创建一个 constexpr 舍入函数,该函数可以在编译时调用。

至于查号码可以用static_assert(695 == UREF_180V, "");

要编译 C++11 代码,请将 -std=c++11 添加到您的编译器选项中。 (您可能必须切换到 C++ 项目,我不完全确定 AtmelStudio 是否支持 C++11,如果不支持,我很抱歉)

【讨论】:

  • 我不确定是否可以在我的工具链中使用С++11。如何使用 C++11 扩展?我应该改变我的工具链吗?或者我可以通过任何命令行选项“打开它”?
  • 首先您必须检查是否可以编译纯 C++。创建一个 .cpp 文件并尝试编译它。如果它不起作用,您可能必须切换到 C++ 工具链或创建一个新的 C++ 项目(我不知道您的 IDE 如何处理此问题)。一旦编译 C++ 工作,查找编译器选项文本字段并将-std=c++11 粘贴到那里并尝试从这个答案编译代码。
【解决方案3】:

请参阅 -fmerge-all-constants 命令、-fgcse、-fsee 或更好的命令,请参阅此处:https://gcc.gnu.org/onlinedocs/gcc-4.2.2/gcc/Optimize-Options.html

尽管如此,正如 welternsturm 所提到的,整数溢出可能是代码中语义错误的一部分

【讨论】:

  • 我不太熟悉这种编译器精简调整...您能否建议我是否应该使用所有这三个命令,或者我应该选择一个或几个取决于哪个对我有用?我已通过您提供给我的链接阅读了描述,但描述很短,我没有足够的知识自行选择它:(
  • 另外:我无法在 IDE 的项目选项中编辑命令之类的选项。这是屏幕截图:goo.gl/glQjfd 你知道如何在 Atmel Studio 中编辑编译器选项吗?
  • gcc 有各种级别的编译器优化,O0、01、O2、O3、Os 等等。在每个级别中都有个人优化,就像我上面提到的三个,是的,您必须选择一个或几个取决于哪个更适合您的目的,但是,如果您愿意,您可以使用一个级别,例如每个示例的 O2,它具有 O1 的所有编译器优化,即 O3 具有所有 O2 优化等。对于每个编译器选项,例如:-ftree-vrp,有一个命令可以将其关闭,例如:-fno-tree-vrp。我对 Atmel Studio 兄弟一无所知,我欠你的,对不起。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-08-22
  • 1970-01-01
  • 1970-01-01
  • 2012-01-28
  • 1970-01-01
  • 2012-12-26
  • 1970-01-01
相关资源
最近更新 更多