You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C++中创建编译期常量全局类?嵌入式场景适配

嵌入式C++中实现编译期构造的常量类/结构体

在嵌入式场景下,要实现和C语言类似的、编译期构造且放在只读数据段的常量实例,C++可以通过constexpr关键字轻松实现,完全避开全局构造函数。下面分两种常用写法说明:

1. 兼容C风格的结构体写法

直接沿用你熟悉的C结构语法,只需要用constexpr替代C中的const(const也能工作,但constexpr明确强制编译期初始化):

#include <cstdint>

// 先定义驱动方法结构体
struct drivermethods {
    void (*init)(void);
    void (*send)(uint8_t);
};

// UART结构体定义
struct UART {
    uintptr_t baseaddr;
    int irqnum;
    const drivermethods* pMethods;
};

// 编译期构造驱动方法实例
constexpr drivermethods driverX = {
    .init = []() { /* 这里写编译期可执行的初始化逻辑 */ },
    .send = [](uint8_t data) { /* 发送逻辑 */ }
};

// 编译期构造UART实例,会被放在只读数据段
constexpr UART uart0 = {
    .baseaddr = 0x40001000,
    .irqnum = 5,
    .pMethods = &driverX
};

这段代码和你C语言的写法几乎一致,但constexpr确保所有初始化都在编译阶段完成,不会生成任何运行时构造代码,实例会被放在只读段(代码段的一部分)。

2. 带封装的C++类写法

如果想要用C++的类封装特性,同样可以通过constexpr构造函数实现编译期初始化:

#include <cstdint>

struct drivermethods {
    void (*init)(void);
    void (*send)(uint8_t);
};

class UART {
public:
    // constexpr构造函数,强制编译期初始化
    constexpr UART(uintptr_t addr, int irq, const drivermethods* methods)
        : baseaddr(addr), irqnum(irq), pMethods(methods) {}

    // 可以添加constexpr成员函数,编译期就能调用
    constexpr uintptr_t getBaseAddr() const { return baseaddr; }

private:
    uintptr_t baseaddr;
    int irqnum;
    const drivermethods* pMethods;
};

constexpr drivermethods driverX = {
    .init = []() {},
    .send = [](uint8_t) {}
};

// 编译期构造UART类实例
constexpr UART uart0(0x40001000, 5, &driverX);

这种写法保留了C++的封装性,同时完全满足编译期构造、无全局构造函数的要求。

关键要点

  • constexpr是核心:它强制编译器在编译阶段完成初始化,确保实例被放在只读段,不会触发运行时构造。
  • 成员类型限制:要编译期构造的对象,成员必须是字面量类型(比如基本类型、指针、简单结构体),不能用需要运行时初始化的类型(比如std::string)。
  • 编译器版本:确保启用C11或更高版本(constexpr在C11引入,C++14/17支持更多场景),嵌入式编译器一般都支持。
  • 只读段验证:可以通过查看编译后的.map文件,确认uart0等实例被放在.rodata段(只读数据段)。

内容的提问来源于stack exchange,提问作者user3696153

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 19:27:24