在没有内存膨胀的情况下将预处理器配置定义迁移到 constexpr
Migrating preprocessor configuration definitions to constexpr without memory bloat
迟到总比不到好:我正在尝试将我的代码库更新为最新的 C++ 标准,现在正试图真正理解 constexpr 语法功能的意图。
但是,我正在努力解决这个问题:在我的一个微控制器项目(没有一些高级标准功能的纯 C++)中,我有一个 配置头文件,其中包含一个相当大的 #define 语句列表允许非开发人员用户配置某些常量值(大多数情况下与设备相关的参数)。示例:
#define SERIAL_DEVICE_XY_BAUD_RATE (9600)
#define MAX_SENSORDATA_BUFFER_LENGTH (250)
在我看来,将其迁移到 constexpr 定义是一个很好的选择(对我来说最重要的是命名空间和这些值的类型安全)。
现在我的问题是:虽然我想保留带有配置常量的单独头文件,但如何在不重复内存分配的情况下使用 constexpr?据我了解,像这样迁移到 constexpr:
constexpr unsigned int device1_baud_rate = 115200;
将给出一个完全独立的(新的)变量,并分配了适当的内存。当在程序中其他地方的 class 的构造函数中使用它时(就像现在使用宏定义一样),它被复制到成员变量,给我留下两个变量分配而不是一个。
我想我错过了一种直接使用此类 constexpr 值的概念,有人能为我指出这个用例的正确方向吗?谢谢!
您始终可以使用像 godbolt 这样的工具来查看编译器创建的内容。如果您检查 this setup 的结果,您将看到编译器将为 #define
和 costexpr
生成相同的输出,如果您仅将它们用作常量,即使没有打开优化:
#include <iostream>
#define DEFINE_CONST (9600)
constexpr unsigned int constexpr_const = 9600;
int main() {
int x = DEFINE_CONST;
int y = constexpr_const;
std::cout << constexpr_const << std::endl;
std::cout << DEFINE_CONST << std::endl;
}
结果:
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 9600 // int x = DEFINE_CONST;
mov DWORD PTR [rbp-8], 9600 // int y = constexpr_const;
// std::cout << constexpr_const << std::endl;
mov esi, 9600
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(unsigned int)
mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
// std::cout << DEFINE_CONST << std::endl;
mov esi, 9600
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
mov eax, 0
leave
ret
迟到总比不到好:我正在尝试将我的代码库更新为最新的 C++ 标准,现在正试图真正理解 constexpr 语法功能的意图。
但是,我正在努力解决这个问题:在我的一个微控制器项目(没有一些高级标准功能的纯 C++)中,我有一个 配置头文件,其中包含一个相当大的 #define 语句列表允许非开发人员用户配置某些常量值(大多数情况下与设备相关的参数)。示例:
#define SERIAL_DEVICE_XY_BAUD_RATE (9600)
#define MAX_SENSORDATA_BUFFER_LENGTH (250)
在我看来,将其迁移到 constexpr 定义是一个很好的选择(对我来说最重要的是命名空间和这些值的类型安全)。
现在我的问题是:虽然我想保留带有配置常量的单独头文件,但如何在不重复内存分配的情况下使用 constexpr?据我了解,像这样迁移到 constexpr:
constexpr unsigned int device1_baud_rate = 115200;
将给出一个完全独立的(新的)变量,并分配了适当的内存。当在程序中其他地方的 class 的构造函数中使用它时(就像现在使用宏定义一样),它被复制到成员变量,给我留下两个变量分配而不是一个。
我想我错过了一种直接使用此类 constexpr 值的概念,有人能为我指出这个用例的正确方向吗?谢谢!
您始终可以使用像 godbolt 这样的工具来查看编译器创建的内容。如果您检查 this setup 的结果,您将看到编译器将为 #define
和 costexpr
生成相同的输出,如果您仅将它们用作常量,即使没有打开优化:
#include <iostream>
#define DEFINE_CONST (9600)
constexpr unsigned int constexpr_const = 9600;
int main() {
int x = DEFINE_CONST;
int y = constexpr_const;
std::cout << constexpr_const << std::endl;
std::cout << DEFINE_CONST << std::endl;
}
结果:
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 9600 // int x = DEFINE_CONST;
mov DWORD PTR [rbp-8], 9600 // int y = constexpr_const;
// std::cout << constexpr_const << std::endl;
mov esi, 9600
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(unsigned int)
mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
// std::cout << DEFINE_CONST << std::endl;
mov esi, 9600
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
mov eax, 0
leave
ret