c++ 类中的静态常量变量和常量变量在存储方面是否有区别



这是我的代码片段:

class modbus {
public:
static const uint8_t modbusHeader = 2;
static const uint8_t modbusCRC = 2;
static const uint8_t modbusPDU = modbusHeader + modbusCRC;
static const uint8_t exceptionBase = 0x80;
static const uint32_t transmitTimeout = 5000;
};

它为我需要在类中创建的 modbus 数据包定义了一些大小。我在嵌入式环境中工作,因此始终存在尺寸优化和考虑因素。因此,我真的希望在闪存的只读部分中只出现一次这些常量值。

我选择将这些变量设置为static但这有必要吗?编译器是否会推断这些值只需要在二进制文件中保存一次,因此在我删除static关键字时只包含一次?

我想,从技术上讲,如果编译器知道你从未在modbus上执行过sizeof,并且从未通过不同的modbus*指针获取这些成员的地址,并且知道它们只用完全相同的琐碎值初始化,它可能会使用"as-if"规则将它们合并为一个,并在存储方面将它们从类中删除。(如果它不能保证其中一件事,就会违反语言规则。

但这是一个艰巨的任务(特别是当你考虑多个翻译单元时(,并且不会真正有用。

所以没有。我不希望这种情况发生。

你确实应该让这些东西static const(也许

会撒一点constexpr(。

代码

#include <cstdint>
class modbus {
public:
static const uint8_t modbusHeader = 2;
};
int main() {
return modbus::modbusHeader;
}

结果在

main:
pushq   %rbp
movq    %rsp, %rbp
movl    $2, %eax
popq    %rbp
ret

#include <cstdint>
class modbus {
public:
const uint8_t modbusHeader = 2;
};
int main() {
return modbus().modbusHeader;
}

结果在

modbus::modbus() [base object constructor]:
push    rbp
mov     rbp, rsp
mov     QWORD PTR [rbp-8], rdi
mov     rax, QWORD PTR [rbp-8]
mov     BYTE PTR [rax], 2
nop
pop     rbp
ret
main:
push    rbp
mov     rbp, rsp
sub     rsp, 16
mov     BYTE PTR [rbp-1], 0
lea     rax, [rbp-1]
mov     rdi, rax
call    modbus::modbus() [complete object constructor]
movzx   eax, BYTE PTR [rbp-1]
movzx   eax, al
leave
ret

至少这里有很大的区别。我将 g++ 9.2 与 -O0 一起使用

如果坚持使用 C++,则必须const限定类的对象,而不是类的成员。然后,您必须确保具有静态存储持续时间的const变量最终以闪存形式呈现给定目标。通常,工具链具有称为"flash-something"的构建。它与链接器而不是编译器相关。如果该部分正常工作,则类的对象是否static并不重要,只要该对象是在文件范围(静态存储持续时间(声明的

。您不应该做的是只限定类成员const,而不是它们所在的对象。因为这可能会导致静默C++膨胀以"CRT"调用的默认构造函数的形式保留在可执行文件中。可以通过单步执行 CRT 中处理调用具有静态存储持续时间的对象的构造函数的部分来验证这一点。

至于让成员static,你应该只需要这样做,就像单例一样,而不是让成员最终进入闪存。

最新更新