由于我对 C 比较陌生,因此我必须为我的项目之一使用以下内容:我必须声明一些全局变量,每次程序在相同的内存地址运行时都必须存储这些变量。我做了一些阅读,我发现我将它声明为“静态”,它将存储在同一个内存位置。
但我的问题是:我能否指出程序在哪里存储该变量。例如:int a 要存储在 0xff520000。这件事能不能做?我在这里搜索过,但没有找到任何相关的例子。如果他们是关于此的一些旧帖子,请分享链接。
谢谢大家。劳伦蒂乌
更新:我使用的是 32uC
由于我对 C 比较陌生,因此我必须为我的项目之一使用以下内容:我必须声明一些全局变量,每次程序在相同的内存地址运行时都必须存储这些变量。我做了一些阅读,我发现我将它声明为“静态”,它将存储在同一个内存位置。
但我的问题是:我能否指出程序在哪里存储该变量。例如:int a 要存储在 0xff520000。这件事能不能做?我在这里搜索过,但没有找到任何相关的例子。如果他们是关于此的一些旧帖子,请分享链接。
谢谢大家。劳伦蒂乌
更新:我使用的是 32uC
在您的 IDE 中,将通过一些链接器文件提供内存映射。它将包含程序中的所有地址。阅读 MCU 手册以查看哪些地址有有效的内存供您使用,然后为您的变量保留一些内存。您必须阅读特定开发平台的文档。
接下来,请注意,将变量映射到特定地址没有多大意义,除非它们是硬件寄存器或驻留在闪存或 EEPROM 中的非易失性变量。
如果这样一个内存位置的内容在执行期间会发生变化,因为它是一个寄存器,或者因为您的程序包含更改 NVM 存储单元的引导加载程序/NVM 编程算法,则必须将变量声明为易失性。否则编译器会在优化时完全破坏你的代码。
特定的编译器很可能有一种非标准的方式来在特定地址分配变量,例如 #pragma 或有时是奇怪的非标准@
运算符。您可以在标准 C 中的固定位置分配变量的唯一明智方法是:
#define MY_REGISTER (*(volatile uint8_t*)0x12345678u)
其中 0x12345678 是其中 1 个字节所在的地址。一旦你有了这样的宏声明,你就可以像使用变量一样使用它:
void func (void)
{
MY_REGISTER = 1; // write
int var = MY_REGISTER; // read
}
大多数情况下,您希望这些变量驻留在全局命名空间中,因此是宏。但是,如果您出于某种原因希望缩小变量的范围,请跳过宏并在代码中手动访问地址:
void func (void)
{
*(volatile uint8_t*)0x12345678u = 1; // write
int var = *(volatile uint8_t*)0x12345678u; // read
}
您可以使用链接器脚本来做这种事情,这在嵌入式编程中很常见。
在 Linux 系统上,由于地址空间随机化,您可能永远不会获得相同的虚拟地址(一种安全功能,可避免依赖于了解您所描述的变量的确切位置的漏洞利用)。
如果它只是您想要的可重复指针,您可以使用 映射特定地址mmap
,但这不能保证。
就像其他答案中提到的那样 - 你不能。但是,您可以有一个解决方法。如果可以在 中初始化全局变量,则main()
可以执行以下操作:
int addr = 0xff520000;
int main()
{
*((int*)addr) = 42;
...
return 0;
}
但是请注意,这非常依赖于您的系统,如果在受保护的环境中运行,您很可能会遇到运行时崩溃。如果您在嵌入式/不受保护的环境中,这可以工作。
不,您不能明确告诉它在内存中存储变量的位置。主要是因为在现代系统上,系统在内存方面做了很多事情,这是你无法控制的。地址布局随机化是一件让这变得非常困难的事情。
如果您使用 XC8 编译器,请根据您的编译器。你可以简单地写 int x @ 0x12 ;
在这一行中,您在内存位置 0x12 中设置 x
您可以声明一个指向特定内存地址的指针,并将该指针的内容用作我想的变量:
int* myIntPointer = 0xff520000;
不在C级。如果使用汇编语言,则可以直接控制内存布局。但是 C 编译器会为您执行此操作。你真的不能乱来。
即使使用汇编,这也只能控制相对布局。虚拟内存可以将其放置在任何(不)方便的物理位置。
您可以使用一些编译器扩展来做到这一点,但这可能不是您想要做的。操作系统会处理你的记忆,并将东西放在它想要的地方。你怎么知道你想要的内存地址会映射到你的程序中呢?如果您在嵌入式平台上,请忽略本段中的所有内容,那么您应该阅读该平台/编译器的手册,或者至少在此处提及它,以便人们可以给出更具体的答案。
此外,静态变量在程序运行时不一定具有相同的地址。许多操作系统使用与位置无关的可执行文件,并在每次执行时随机化地址空间。