优化#define与静态const(在avr-gcc中)

时间:2015-03-05 13:36:32

标签: c gcc optimization macros const

虽然我在一般范围内欢迎这方面的答案,但我主要是要求avr-gcc使其不太广泛。

我已经查看了一些问题,尤其是thisthis。他们主要关注语义差异,例如:不能使用static const代替常量表达式。然而,尽管一般都在谈论内存分配,但他们并没有谈论优化。

让我们看一个例子:

typedef struct {
    GPIO_TypeDef *port;
    uint8_t  pin;
} gpio_pin_t;

static inline void gpio_pin_set(gpio_pin_t gpio, bool set) {
    if(set) GPIO_SetBits  (gpio.port, 1 << gpio.pin);
    else    GPIO_ResetBits(gpio.port, 1 << gpio.pin);
}

//elsewhere including above definitions

static const gpio_pin_t gpio_pin = {GPIOE, 8};

void some_function(bool enable) {
    gpio_pin_set(gpio_pin, enable);
}

正如你所看到的,我使用结构,所以第三种既定方式(枚举)不是一个选项

我可以期待gcc优化内联函数中的gpio.portgpio.pin访问吗?如果没有,为什么会这样,并且gcc在看到consts时会应用其他优化吗?

完全的一般性,使用static const变量代替定义,,尤其是超越简单的整数常量,我会失去什么优化?

2 个答案:

答案 0 :(得分:3)

这取决于编译器的实现。

如果您从未接受它的地址且未导出符号(对于C,默认情况下,因此您必须使用static),然后优化程序应启动并优化它。对于简单类型(intfloat),您可以合理地期望它可以全面工作,但对于struct - 更好地检查编译器的作用。对于像我的GCC这样的简单结构优化它,消除结构并直接传递它的值,将常量加载到CPU寄存器。对于较大的结构,它可能决定它是不值得的。

您可以生成要检查的代码的汇编列表:

avr-gcc -O<opt> -S somefile.c

gcc -O<opt> -S somefile.c

不要忘记优化级别!

使用#define很糟糕,因为预处理器非常愚蠢 - 它只是在编译之前逐字替换代码。使用const购买可以更好地输入安全性。考虑这个例子:

#define BYTE_VALUE 257
static const uint8_t sc_value = 257; // at least will show warning
int my_byte = BYTE_VALUE; // no warning, but obviously it's a bug!

答案 1 :(得分:2)

关于抽象:

为什么你在大量的抽象层中淹没了这么简单的东西?您可以放心地假设每个C程序员都知道

的含义
PORT |= (1<<pin);
PORT &= ~(1<<pin);

就C程序员而言,这和代码一样可读。通过将此代码隐藏在抽象层中,可以使代码对C程序员的可读性降低,尽管非程序员可能会更容易阅读。但是你希望前者阅读你的代码,而不是后者。

就效率而言,上述也是最快的。编译器很可能会将这些代码直接转换为单个位设置/位清除汇编程序指令。

所以我的建议是抛弃所有的抽象。您不希望将硬件隐藏在嵌入式C程序员之外。您需要隐藏的是特定的硬件实现,因此他们无需为每个新项目重新发明轮子。

一种这样的抽象是在编写与硬件无关的API层时。例如void led_set (bool lit);。此功能将点亮电路板上的LED。您将它放在抽象文件led.h中,该文件没有相应的.c文件。因为.c文件仅针对您的特定项目实现:在my_led.c中,您将拥有实际实现,直接访问GPIO寄存器,设置数据方向和数据。拉电阻调节器,处理信号极性等。


关于您的具体问题:

无法保证GCC会像您期望的那样内联该函数:inline关键字已经过时了,因为现在编译器在决定何时内联函数时比程序员更聪明。我会说很有可能,因为你在编译时启用了最大优化。找出答案的唯一方法就是尝试。

但是,编译器是否内联此函数并不是最重要的。您可能不会有这样极端的实时要求,函数调用开销会影响您的程序。我们在这里谈论几十纳秒:即使是电路板上的数字电子集成电路也不会对这些额外的CPU滴答作出足够快的响应以产生影响。

我每天都在使用基于MCU的实时嵌入式系统,甚至在这些系统中,你很少遇到像这样的极端代码优化很重要的情况。如果你这样做,你将使用DSP,而不是常规MCU,绝对不是AVR。

更重要的是,你的static const将常量的范围缩小到本地文件,因此没有其他人需要关注它,也不会使全局命名空间混乱。这是一个很好的编程实践,良好的编程实践在10次中有9次胜过手动代码优化。