C STM32内存中如何表示常量字符和字符指针

C STM32内存中如何表示常量字符和字符指针,c,pointers,stm32,C,Pointers,Stm32,变量所指向的字符串是在数据内存还是在程序内存中,MCU现在是如何处理的? 当我将const char*强制转换为char*时(例如调用strlen函数),编译器会做什么? char*可以用作char*和const char*而不会造成任何性能损失吗?STM32s使用一个平坦的32位地址空间,因此RAM和程序内存(闪存)位于同一逻辑空间中 皮质核心当然知道哪种类型的内存在哪里,可能是通过被访问地址触发的硬件地址解码器。当然,这远远超出了C所关心的范围 删除const不是运行时操作,因此不应该有性能

变量所指向的字符串是在数据内存还是在程序内存中,MCU现在是如何处理的?
当我将
const char*
强制转换为
char*
时(例如调用
strlen
函数),编译器会做什么?

char*
可以用作
char*
const char*
而不会造成任何性能损失吗?

STM32s使用一个平坦的32位地址空间,因此RAM和程序内存(闪存)位于同一逻辑空间中

皮质核心当然知道哪种类型的内存在哪里,可能是通过被访问地址触发的硬件地址解码器。当然,这远远超出了C所关心的范围


删除
const
不是运行时操作,因此不应该有性能开销。当然,删除
const
是不好的,因为在某个地方,你可能会让某人相信
const
指针意味着数据不会被写入,而违背这一承诺可能会导致不好的情况发生。

以一个带有1MB闪存/ROM内存和192KB RAM内存(128KB SDRAM+64KB CCM)的STM32F4为例-内存映射如下所示:

  • 闪存/ROM-0x08000000到0x080FFFFF(1MB)
  • 内存-0x20000000到0x2001FFF(128KB)
为了解释的简单性,我将不在这里介绍更多具有单独地址空间的区域。这些存储器包括备份SRAM和CCM RAM,仅举两个例子。此外,每个区域可以被进一步划分为部分,例如被划分为bss、stack和heap的RAM

现在谈谈关于字符串及其位置的问题-常量字符串,例如:

const char *str = "This is a string in ROM";
都放在闪存中。在编译过程中,编译器会放置一个引用此类字符串的临时符号。稍后在链接阶段,链接器(它知道每个内存段的具体值)在每个段中一个接一个地放置所有数据(程序、常量数据等),一旦它知道每个这样的对象的具体值,就用具体值替换编译器放置的符号,这些值随后出现在二进制文件中。因此,稍后在运行时完成上述赋值时,
str
变量只需分配一个由链接器推导的常量值(例如0x08001234),该常量值直接指向字符串的第一个字节

当涉及到动态分配的值时——无论何时调用malloc或new,都会完成类似的任务。假设有足够的内存可用,您将获得RAM中请求的内存块的地址,并且这些计算将在运行时进行

至于关于
const
限定符的问题,一旦代码被执行,它就没有意义了。例如,在运行时,
strlen
函数将简单地逐字节检查内存,从传递的位置开始,在遇到二进制
0
时结束。分析字节的“类型”无关紧要,因为一旦代码转换为字节码,这些信息就会丢失。关于上下文中的
const
,函数参数中出现的
const
限定符表示该函数不会修改字符串的内容。如果它试图这样做,则会引发编译错误,除非它隐式执行对非常量类型的转换。当然,您可以将非常量变量作为函数的常量参数传递。但是,另一种方法——将常量参数传递给非常量函数——将引发错误,因为此函数可能会修改您指向的内存的内容,您通过使其
const
隐式指定为不可修改


因此,总结并回答您的问题:您可以根据需要进行任意多的强制转换,而这不会在运行时反映出来。它只是一条指令,让编译器在类型检查期间以不同于原始变量的方式处理给定变量。但是,通过执行隐式转换,您应该意识到这种转换可能是不安全的。

如果您的字符串是真正的只读字符串,则无论是否使用const,都将改变它是位于.data还是.rodata或其他只读节(.text等)中。基本上它是在闪存中还是在ram中

如果我没记错的话,这些部件上的闪存充其量有一个额外的等待状态,或者基本上是ram速度的一半…充其量。(一般来说,MCU很常见,但也有例外)。如果您在较慢的时钟范围内运行,那么如果您提高了时钟,ram的性能将比闪存有所提高。因此,对于任何通过该字符串进行解析的代码来说,将其放在flash(const)vs sram中都会比较慢


这假设您的链接器脚本和引导程序是这样的。数据实际上是在引导时复制到ram…

侧注:
strlen
已经需要
const char*str
。你可以不施法通过常量和非常量版本。而且,你的问题太广泛了。常量可以影响编译器/链接器放置变量的位置(RAM vs ROM),但这一切都取决于您的工具和处理器体系结构。根据tag wiki,STM32涵盖了各种ARM Cortex内核,而您甚至还没有指定正在使用的编译器。在闪存与任何其他内存一样只是地址映射的系统上,
char*
const char*
之间生成的机器代码没有区别。如果您使用
char*const
,那么有一个显著的区别,即编译器将尝试在NVM中分配指针本身,而不是在RAM中。您不应该使用不必要的强制转换。您始终可以将
char*
分配给
const char*
,但不能以另一种方式分配(您不应该通过强制转换来强制执行此操作)。@Lundin:这同样适用于对象
const char*