GCC C++ (ARM) 和指向结构体字段的 const 指针

2024-05-17

假设有一个简单的测试代码

typedef struct
{
    int first;
    int second;
    int third;
} type_t;

#define ADDRESS 0x12345678

#define REGISTER ((type_t*)ADDRESS)

const int data = (int)(&REGISTER->second)*2;

int main(void)
{
    volatile int data_copy;

    data_copy = data;

    while(1) {};
}

它是在 CodeSourcery G++ (gcc 4.3.2) 中为裸机 ARM 编译的。它还有一个非常标准的链接描述文件。

当用 C 语言编译时(如 main.c),对象“数据”将按预期进入 Flash。当用 C++ 编译时(如 main.cpp),该对象进入 RAM,并添加额外的代码,其作用只不过是将值从闪存复制到 RAM(该值已经计算出来,只需复制!)。所以编译器可以计算地址,但不知何故不想“只是 问题的根源是地址的乘法 - 没有“*2”乘法,两个版本都按预期工作 - “数据”被放置在闪存中。此外 - 当“数据”声明为:

const int data = (int)(REGISTER)*2;

一切都很好。

C 和 C++ 编译的所有文件都是相同的,唯一的区别是对编译器的调用 - main.cpp 的 g++,main.c 的 gcc(警告级别不同,c++ 禁用了 RTTI 和异常)。

有没有简单而优雅的方法来克服这个“C++ 问题”?我确实需要这样的操作来创建 Cortex-M3 位带区域中的位地址常量数组。这是一个错误,还是 C++ 编译器的一些奇怪的限制?

我知道我可以在“C”文件中创建数据对象,然后“extern”将它们包含在 C++ 中,但这不是很优雅 [;

谢谢大家的帮助!


你有几个问题。为什么要获取一个地址,将其转换为整数,然后乘以 2?您永远不应该通过地址相乘或将地址存储为整数。您应该对指针执行的唯一算术是减去它们(以获得偏移量),或者添加带有偏移量的指针以获得另一个指针。

在 C++ 中,全局值初始化的规则比 C 中稍微宽松一些。在 C 中,值需要初始化为编译时常量;在 C 中,值需要被初始化为编译时常量。结果,编译器可以放置const只读存储器中的全局值。在 C++ 中,值可以初始化为不一定是编译时常量的表达式,并且允许编译器在运行时生成代码来计算初始值。该初始化代码在进入之前被调用main(),类似于全局对象的构造函数。

由于您正在使用常量地址,并且您知道一个有多大int在你的平台上(我假设是 32 位),你应该这样做:

接下来,您使用volatile关键字完全错误。volatile告诉编译器不要将变量保存在寄存器中——每次读取变量时都应该从内存中重新加载变量,并且每次写入变量时都应该将其完全写入内存。声明局部变量data_copy as volatile实际上是无用的,除非您期望另一个线程或信号处理程序开始意外地修改它(非常可疑)。更远,data_copy只是地址的副本,而不是您要读取的寄存器的内容。

你什么should正在做的就是声明REGISTER作为指向 volatile 的指针——这是其明确的目的之一volatile,用于访问内存映射寄存器。您的代码应如下所示:

#define REGISTER (*(volatile type_t *)ADDRESS)
#define DATA (*(const volatile int *)((ADDRESS+4)*2))

这使得当你做这样的事情时:

REGISTER.first = 1;
REGISTER.first = 2;
int x = REGISTER.second;
int y = DATA;

它总是做正确的事情:将 1 写入 0x12345678,将 2 写入 0x12345678,从 0x1234567c 读取,以及从 0x2468acf8 读取。这volatile关键字确保这些读取和写入始终发生,并且它们不会被优化:编译器不会删除第一个写入REGISTER.first,如果它是一个常规变量,这将是多余的。

EDIT

作为对你的评论的回应,请参阅安德鲁·梅迪科对你的评论的回应——你真的在乘以不同之处两个指针之间相差2,这是可以的。请注意您的数据类型。我也从未提到过任何有关内核的事情。

您可以使用 gcc 将变量放入特定的数据部分section属性 http://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html#index-g_t_0040code_007bsection_007d-variable-attribute-2413:

const volatile int *data __attribute__((section("FLASH")) = /* whatever */;

使用正确的部分名称。如果您不确定那是什么,请获取 C 编译器生成的目标文件(您说将其放在正确的部分中),运行nm并查看 C 编译器将其放入哪个部分。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

GCC C++ (ARM) 和指向结构体字段的 const 指针 的相关文章

随机推荐