STM32中const char和char指针在内存中是如何表示的

How are const char and char pointers represented in memory in STM32

MCU怎么知道a变量指向的字符串是在数据内存还是在程序内存?
当我将 const char * 转换为 char * 时(例如调用 strlen 函数时),编译器会做什么?
char * 可以用作 char *const char * 而没有任何性能损失吗?

STM32s使用平面32位地址space,所以RAM和程序存储器(闪存)在同一个逻辑space。

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

删除 const 不是 运行 次操作,因此应该没有性能开销。当然,删除 const 不好的 ,因为在某些地方你冒着有人真的相信 const 指针意味着数据不会被写入的风险,然后继续这个承诺会让坏事发生。

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

  • Flash/ROM - 0x08000000 到 0x080FFFFF (1MB)
  • RAM - 0x20000000 到 0x2001FFFF (128KB)

还有更多具有独立地址空间的区域,为了解释简单起见,我不会在此处进行介绍。此类存储器包括备份 SRAM 和 CCM RAM,仅举两例。另外,每个区域还可以进一步细分,比如RAM被划分为bss、stack和heap。

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

const char *str = "This is a string in ROM";

都放在闪存中。在编译期间,编译器会放置一个引用此类字符串的临时符号。稍后在链接阶段,链接器(知道每个内存部分的具体值)一个接一个地在每个部分中放置所有数据(程序、常量数据等),并且 - 一旦它知道每个此类对象的具体值 -用具体值替换编译器放置的那些符号,然后出现在您的二进制文件中。因此,稍后在运行时完成上述分配后,您的 str 变量将被简单地分配一个由链接器推导的常量值(例如 0x08001234),该值直接指向字符串的第一个字节。

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

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

所以总结并回答你的问题:你可以随心所欲地进行转换,这不会在运行时反映出来。它只是指示编译器在类型检查期间以不同于原始变量的方式对待给定变量。通过进行隐式转换,您应该意识到这种转换可能是不安全的。

无论是否使用 const,假设您的字符串确实是只读的,将改变它是否位于 .data 或 .rodata 或其他只读部分(.text 等)中。基本上它是在闪存中还是在 ram 中。

如果我没记错的话,这些部件上的闪光灯最多有一个额外的等待状态,或者基本上是 ram 速度的一半......最多。 (一般来说对于 mcus 来说相当普遍,但也有例外)。如果你 运行 在较慢的时钟范围内,你提高时钟的 ram 性能与闪存相比将会提高。因此,对于通过该字符串解析的任何代码,将它放在 flash (const) 与 sram 中都会变慢。

这假设您的链接描述文件和 bootstrap 是这样的。数据实际上在启动时被复制到 ram...