有些架构有多个地址空间,值得注意的例子是真正的Harvard架构,但是例如OpenCL也有这个属性。
C编译器可能会为此提供一些解决方案,其中一个是命名地址空间,支持特殊指针限定符来指示指针的地址空间,但也可能存在其他解决方案。
我不知道它们,在我使用的架构(8位AVR)上,还有另一个解决问题的解决方案,专门的宏(pgmspace.h
)来处理ROM中的数据。但是没有对这些进行类型检查,并且它们(在我看来)使代码难看,所以在我看来,使用命名地址空间是一种优越的,甚至可能更便携的方式来处理问题(便携式)通过为地址空间限定符提供空定义,可以轻松地将这样的软件移植到具有单个地址空间的目标。)
然而,在之前我从其可用性中学到的问题中,建议使用命名地址空间的解决方案受到严重贬低,在此处:How to make two otherwise identical pointer types incompatible
Downvoters没有提供任何解释,我也没有找到任何自己,对我而言,看起来命名地址空间是处理问题的一种很好且功能完善的方式。
有人可以提供解释吗?为什么不应该使用命名地址空间? (赞成具有多个不同地址空间的目标上可用的任何其他方法)
答案 0 :(得分:3)
另一种方法是窃取Linux内核和smatch等工具中使用的技术。
Linux已定义为
#define __user
这意味着代码可以说像int foo(const __user char * p)。编译器会忽略__user,但是使用像smatch这样的工具来确保指针不会在名称空间之间意外地徘徊。
答案 1 :(得分:1)
这些问题显而易见:它们只适用于gcc编译器。
在嵌入式系统分支中,有许多不同的编译器,每个都提供了自己独特的,不可移植的方式来实现这一点。有时这很好(大多数嵌入式项目永远不会被移植到不同的编译器)但是从通用的观点来看,它不是。
(扩展地址也存在同样的问题 - 例如,如果您使用具有超过64kib可寻址内存的8位或16位MCU。编译器则使用各种非标准扩展,例如near
和{ {1}}。)
这些问题的一个解决方案是围绕特定于编译器的行为制作一个“包装器”,通过创建硬件抽象层(HAL),您可以在其中指定用于在闪存中存储数据的类型为far
或一些这样的,然后从你的HAL包括一个包含实际typedef的编译器特定的头文件,如flash_byte_t
。例如,应用程序包括“compiler.h”,而这个应用程序又包含“gcc.h”。这样,当你切换编译器时,你只需要重写一个小的头文件。
事实证明,C允许typedef const __flash uint8_t flash_byte_t;
就好了,即使这已经是constdef为const。在C中有一个特殊的奇怪规则,即你可以在声明中多次添加相同的限定符。因此const flash_byte_t
相当于const const int x
。这意味着如果用户提出额外的const限定,那就没问题了。
请注意,由于其奇怪的哈佛模型,AVR在这里主要是一个特殊的例外。
否则,大多数编译器都使用了行业事实上的标准约定:所有具有静态存储持续时间的const int x
限定变量应该在flash中分配。当然,C标准不保证这一点(它超出了标准范围),但大多数嵌入式编译器的行为都是这样的。