1

我在 16 位目标平台上使用 avr-gcc

我想做这样的事情:

#define F_CPU 16000000
#define MIN_UPDATES_PER_REV 100
#define MAX_RPM 10000
#define UPDATE_PERIOD_cy ( F_CPU*60 / (MIN_UPDATES_PER_REV*MAX_RPM) )

正如预期的那样,我收到一个溢出错误,因为 MIN_UPDATES_PER_REV*MAX_RPM 的计算结果为 0xf4240:

bldc.h:9:40: warning: integer overflow in expression [-Woverflow]
#define UPDATE_PERIOD_cy ( F_CPU*60 / (MIN_UPDATES_PER_REV*MAX_RPM) )
                                                          ^

如果我将常量强制为 32 位并在折叠后转换回 uint16_t,事情就会解决,尽管我失去了 -Woverflow 的好处:

#define UPDATE_PERIOD_cy (uint16_t)( (uint32_t)F_CPU*60 / ((uint32_t)MIN_UPDATES_PER_REV*MAX_RPM) ))

我可以强制 gcc 在恒定折叠期间处理较大的中间值吗?

我可以强制预处理器为我做持续折叠吗?

是否有我应该了解的最佳实践?

4

2 回答 2

2

您可以通过添加后缀来指定常量的大小,例如100UL100LL

解决当前问题的另一种方法是重新排序表达式:

#define UPDATE_PERIOD_cy ( F_CPU*60 / MIN_UPDATES_PER_REV / MAX_RPM) )

这将给出相同的结果,但避免了溢出的大中间值。

于 2016-09-25T23:14:12.207 回答
0

我可以强制 gcc 在恒定折叠期间处理较大的中间值吗?

不,你不能这样做。始终应用通用 C 规则。含义MIN_UPDATES_PER_REV将被评估为 uint16 和MAX_RPMuint8。乘法的结果不适合 uint16,你会得到 -Woverflow。

我可以强制预处理器为我做持续折叠吗?

预处理器只做宏替换,GCC 做常量折叠。如果问题是关于强制 GCC 进行常量折叠,那么即使没有优化标志,GCC 也会进行常量折叠。

是否有我应该了解的最佳实践?

这是一个主观问题。(我认为您已经使用了最佳方式来进行强制转换。由于它在编译时进行了优化,因此您没有执行成本过高)。

于 2016-09-25T08:10:58.577 回答