c++ - 如何在 C++ 类内存结构中创建 "spacer"?

标签 c++ c memory-management low-level bare-metal

问题

低级裸机嵌入式上下文中,我想在内存中创建一个空白空间,在 C++ 结构中并且没有任何名称,以禁止用户访问这样的内存位置.

现在,我通过放置一个丑陋的 uint32_t :96; 来实现它bitfield 可以方便地代替三个单词,但它会从 GCC 发出警告(Bitfield too large to fit in uint32_t),这是非常合法的。

虽然它工作正常,但当您想要分发包含数百个此类警告的库时,它不是很干净......

我该如何正确地做到这一点?

首先为什么会出现问题?

我正在进行的项目包括定义整个微 Controller 系列 (STMicroelectronics STM32) 的不同外设的内存结构。为此,结果是一个包含多个结构 union 的类,这些结构定义了所有寄存器,具体取决于目标微 Controller 。

一个非常简单的外围设备的简单示例如下:通用输入/输出 (GPIO)

union
{

    struct
    {
        GPIO_MAP0_MODER;
        GPIO_MAP0_OTYPER;
        GPIO_MAP0_OSPEEDR;
        GPIO_MAP0_PUPDR;
        GPIO_MAP0_IDR;
        GPIO_MAP0_ODR;
        GPIO_MAP0_BSRR;
        GPIO_MAP0_LCKR;
        GPIO_MAP0_AFR;
        GPIO_MAP0_BRR;
        GPIO_MAP0_ASCR;
    };
    struct
    {
        GPIO_MAP1_CRL;
        GPIO_MAP1_CRH;
        GPIO_MAP1_IDR;
        GPIO_MAP1_ODR;
        GPIO_MAP1_BSRR;
        GPIO_MAP1_BRR;
        GPIO_MAP1_LCKR;
        uint32_t :32;
        GPIO_MAP1_AFRL;
        GPIO_MAP1_AFRH;
        uint32_t :64;
    };
    struct
    {
        uint32_t :192;
        GPIO_MAP2_BSRRL;
        GPIO_MAP2_BSRRH;
        uint32_t :160;
    };
};

所有GPIO_MAPx_YYY是一个宏,定义为 uint32_t :32或寄存器类型(专用结构)。

在这里您可以看到 uint32_t :192;效果很好,但会触发警告。

到目前为止我所考虑的:

我可能已经用几个 uint32_t :32; 替换了它(此处为 6),但我有一些极端情况,我有 uint32_t :1344; (42) (除其他外)。因此,即使结构生成是脚本化的,我也不愿在 8k 其他行之上添加大约 100 行。

确切的警告信息类似于: width of 'sool::ll::GPIO::<anonymous union>::<anonymous struct>::<anonymous>' exceeds its type (我就是喜欢它的阴暗面)。

我宁愿通过简单地删除警告来解决这个问题,而是使用

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-WTheRightFlag"
/* My code */
#pragma GCC diagnostic pop

可能是一个解决方案...如果我找到 TheRightFlag .但是,正如 this thread 中指出的那样, gcc/cp/class.c用这个悲伤的代码部分:

warning_at (DECL_SOURCE_LOCATION (field), 0,
        "width of %qD exceeds its type", field);

这告诉我们没有 -Wxxx标记以删除此警告...

最佳答案

C++ 方式怎么样?

namespace GPIO {

static volatile uint32_t &MAP0_MODER = *reinterpret_cast<uint32_t*>(0x4000);
static volatile uint32_t &MAP0_OTYPER = *reinterpret_cast<uint32_t*>(0x4004);

}

int main() {
    GPIO::MAP0_MODER = 42;
}

由于 GPIO 命名空间,您可以自动完成,并且不需要虚拟填充。甚至,更清楚发生了什么,因为您可以看到每个寄存器的地址,您根本不必依赖编译器的填充行为。

关于c++ - 如何在 C++ 类内存结构中创建 "spacer"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53109888/

相关文章:

c++ - 另一个函数内的函数前向声明

c++ - 从逆序C++访问 vector 时发生运行时错误

c - fgets() 和 scanf ("%[^\n]")都被跳过

c - 从txt文件C中读取整数

c - 重新编码 malloc 和页面大小

windows - 是否有适用于 x64 Windows 的 mem.exe 版本?

c++ - 在另一个对象类中的 vector 中调用对象类方法

c++ - 如何在编译期间输出诊断消息以告知调用了哪个重载函数

c - 如何从内联汇编器调用 Win32 API 函数?

c++ - 在 C++ 中定义可以容纳六个值的最小可能数据类型