你有几个问题。为什么要获取一个地址,将其转换为整数,然后乘以 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 编译器将其放入哪个部分。