在某些体系结构上,对于其他相同的对象,可能需要有不同的指针类型。特别是对于哈佛架构CPU,您可能需要这样的东西:
uint8_t const ram* data1;
uint8_t const rom* data2;特别是这是在MPLAB C18 (现在停止使用)中对ROM / RAM指针的定义。它甚至可以定义如下:
char const rom* ram* ram strdptr;这意味着在RAM中有一个指针指向ROM中的字符串(使用ram是不必要的,因为在默认情况下,这个编译器会在RAM中添加所有内容,只是为了清晰起见)。
这种语法的好处是,当您试图以不兼容的方式分配ROM位置时,编译器能够提醒您,例如将ROM位置的地址分配给指向RAM的指针(因此类似于data1 = data2;,或者使用RAM指针将ROM指针传递给函数将产生错误)。
与此相反,在AVR的AVR-8中,没有这种类型的安全性,因为它提供访问ROM数据的功能。无法区分指向RAM的指针和指向ROM的指针。
在某些情况下,这种类型的安全性将非常有利于捕获编程错误。
是否有办法以某种方式向指针添加类似的修饰符(例如,通过预处理器,扩展到可以模仿这种行为的东西)来达到这个目的?甚至是对不适当的访问发出警告的东西?(在avr-gcc的情况下,尝试在不使用ROM访问功能的情况下获取值)
发布于 2018-04-23 12:34:11
由于我收到了几个关于提供解决方案的不同妥协的答案,所以我决定将它们合并在一起,概述每种解决方案的优缺点。所以你可以选择最适合你特定情况的
命名地址空间
对于解决这个问题的特殊问题,并且只有在AVR-8微型上的ROM和RAM指针的情况下,最合适的解决方案是这个。
这是一个C11的提议,它没有进入最终的标准,但是有一些C编译器支持它,包括avr用于8位avr。
相关文档可以访问这里 (在线GCC手册的一部分,还包括使用此扩展的其他体系结构)。与其他解决方案(如pgmspace.h中的函数类宏用于AVR-8)相比,它是值得推荐的,因此编译器可以进行适当的检查,同时访问由保留明确和简单的数据所指向的数据。
特别是,如果您有类似的问题从提供某种命名地址空间的编译器移植东西,比如MPLAB C18,这可能是最快和最干净的方法。
上面移植的指针如下所示:
uint8_t const* data1;
uint8_t const __flash* data2;
char const __flash** strdptr;(如果可能的话,可以使用适当的预处理定义来简化过程)
(Olaf的原答覆)
结构封装,内部指针
这种方法的目的是通过将指针封装在结构中来加强指针的分型。其目的是通过接口传递结构本身,通过接口编译器可以对它们执行类型检查。
指向字节数据的“指针”类型可能如下所示:
typedef struct{
uint8_t* ptr;
}bytebuffer_ptr;可按以下方式访问指定的数据:
bytebuffer_ptr bbuf;
(...)
bbuf.ptr = allocate_bbuf();
(...)
bbuf.ptr[index] = value;接受这种类型并返回该类型的函数原型如下所示:
bytebuffer_ptr encode_buffer(bytebuffer_ptr inbuf, size_t len);(dvhh的原答覆)
结构封装,外部指针
类似于上面的方法,它的目的是通过将指针封装在结构中来加强指针的类型,但是以一种不同的方式提供了一个更健壮的约束。要指向的数据类型是封装的。
指向字节数据的“指针”类型可能如下所示:
typedef struct{
uint8_t val;
}byte_data;可按以下方式访问指定的数据:
byte_data* bbuf;
(...)
bbuf = allocate_bbuf();
(...)
bbuf[index].val = value;接受这种类型并返回该类型的函数原型如下所示:
byte_data* encode_buffer(byte_data* inbuf, size_t len);(隆丁的原答覆)
我应该使用哪个?
这方面的命名地址空间不需要太多的讨论:如果您只想处理目标处理地址空间的一个频谱,那么它们是最合适的解决方案。编译器将为您提供所需的编译时检查,您不需要进一步发明任何东西。
但是,如果出于其他原因,您对结构包装感兴趣,则可能需要考虑以下事项:
const,这对于创建健壮的接口非常重要(您可以使数据仅供函数const读取)。谢谢你所有的答案!
发布于 2018-04-09 12:59:00
一个窍门是将指针包装在一个结构中。指向struct的指针比指向基本数据类型的指针具有更好的类型安全性。
typedef struct
{
uint8_t ptr;
} a_t;
typedef struct
{
uint8_t ptr;
} b_t;
const volatile a_t* a = (const volatile a_t*)0x1234;
const volatile b_t* b = (const volatile b_t*)0x5678;
a = b; // compiler error
b = a; // compiler error发布于 2018-04-09 12:57:39
对于RAM和ROM,可以将指针封装在不同的结构中,使类型不兼容,但包含相同类型的值。
struct romPtr {
void *addr;
};
struct ramPtr {
void *addr;
};
int main(int argc, char **argv) {
struct romPtr data1 = {NULL};
struct romPtr data3 = data1;
struct ramPtr data2 = data1; // <-- gcc would throw a compilation error here
}在汇编期间:
$ cc struct_test.c
struct_test.c: In function ‘main’:
struct_test.c:12:24: error: invalid initializer
struct ramPtr data2 = data1;
^~~~~当然,为了简洁起见,可以使用typedef的结构。
https://stackoverflow.com/questions/49733195
复制相似问题