只写指针types
我正在为embedded式系统编写软件。
我们使用指针访问FPGA器件的寄存器。
一些寄存器是只读的,而另一些是只写的。
只读寄存器在读取时会产生未定义的值。
我想定义一个指针types,它允许编译器检测何时从只写寄存器(又名解引用)读取值。
只能使用C语言语法创build只写指针吗?
(我们正在开发使用C的第一个原型,但在第二代移植到C ++。)
如何在C ++中创build高效的只写指针? (请记住,这不是跟踪dynamic内存中的项目,而是访问硬件地址。)
该代码用于安全性和质量最为关注的embedded式系统中。
我可能会写一个微小的包装类为每个:
template <class T> class read_only { T volatile *addr; public: read_only(int address) : addr((T *)address) {} operator T() volatile const { return *addr; } }; template <class T> class write_only { T volatile *addr; public: write_only(int address) : addr ((T *)address) {} // chaining not allowed since it's write only. void operator=(T const &t) volatile { *addr = t; } };
至less假设你的系统有一个合理的编译器,我期望这两个都被优化,所以生成的代码与使用原始指针是无法区分的。 用法:
read_only<unsigned char> x(0x1234); write_only<unsigned char> y(0x1235); y = x + 1; // No problem x = y; // won't compile
我已经使用了很多硬件,其中一些具有“只读”或“只写”寄存器(或根据您是否读取或写入寄存器而有不同的function,当有人决定执行时, reg; = 4;“而不是记住它应该有的值,设置第2位并写入新的值,就像你应该试试debugging那些随机位出现和从寄存器中消失的硬件一样,你不能读! )到目前为止,我还没有看到任何阻止从只写寄存器读取或者写入只读寄存器的尝试。
顺便说一下,我是否说过只有“只写”寄存器是一个非常不好的主意,因为你不能回读来检查软件是否正确设置了寄存器,这使得debugging真的很难 – 而且写驱动程序的人不喜欢用两行VHDL或Verilog代码来debugging可能变得非常简单的难题。
如果您对寄存器布局有一些控制权,那么我build议您将“只读”寄存器放在一个4KBalignment的地址中,并且在另一个4KBalignment的地址中“写入”寄存器(大于4KB很好)。 然后你可以编程硬件的内存控制器来防止访问。
或者,如果正在读取不应该被读取的寄存器,或者写入不应该被写入的寄存器,则让硬件产生中断。 我认为硬件确实会产生其他用途的中断?
使用各种C ++解决scheme所提出的其他build议也很好,但并不能阻止那些直接使用寄存器的人,所以如果这真的是一个安全问题(而不是“让我们变得尴尬”),那么你应该有硬件来防止硬件的误用。
我将使用结构的组合来解释registry和一对函数来处理它们。
在fpga_register.h
你会有类似的东西
#define FPGA_READ = 1; #define FPGA_WRITE = 2; typedef struct register_t { char permissions; } FPGARegister; FPGARegister* fpga_init(void* address, char permissions); int fpga_write(FPGARegister* register, void* value); int fpga_read(FPGARegister* register, void* value);
用xor中的READ和WRITE来表示权限。
比在fpga_register.c
你要定义一个新的结构
typedef struct register_t2 { char permissions; void * address; } FPGARegisterReal;
所以你可以返回一个指向它的指针,而不是指向FPGARegister
上fpga_init
的指针。
然后,在fpga_read
和fpga_write
检查权限和
- 如果允许操作,则将
FPGARegister
从参数中转换回FPGARegisterReal
,执行所需的操作(设置或读取值)并返回成功代码 - 如果操作不允许,只需返回一个错误代码
这样,包括头文件在内的任何人都不能访问FPGARegisterReal
结构,因此不能直接访问寄存器地址。 显然,我们可以破解它,但我相信这样的故意黑客并不是你真正关心的问题。
在C中,可以使用指向不完整types的指针来防止所有取消引用:
/* writeonly.h */ typedef struct writeonly *wo_ptr_t;
/* writeonly.c */ #include "writeonly.h" struct writeonly { int value }; /*...*/ FOO_REGISTER->value = 42;
/* someother.c */ #include "writeonly.h" /*...*/ int x = FOO_REGISTER->value; /* error: deref'ing pointer to incomplete type */
只有writeonly.c
,或者通常任何具有struct writeonly
,都可以解引用指针。 当然,这个代码也可能意外地读取了这个值,但是至less所有其他的代码都不能将这些指针一起解除引用,同时能够传递这些指针并将它们存储在variables,数组和结构中。
writeonly.[ch]
可以提供写入值的函数。
我在C中看不到优雅的方式。然而,我看到了一种做法:
#define DEREF_PTR(type, ptr) type ptr; \ typedef char ptr ## _DEREF_PTR; #define NO_DEREF_PTR(type, ptr) type ptr; \ #define DEREFERENCE(ptr) \ *ptr; \ {ptr ## _DEREF_PTR \ attempt_to_dereference_pointer_ ## ptr;} int main(int argc, char *argv[]) { DEREF_PTR(int*, x) NO_DEREF_PTR(int*, y); DEREFERENCE(x); DEREFERENCE(y); // will throw an error }
这有利于给你静态错误检查。 当然,使用这种方法,你必须出去修改所有的指针声明来使用macros,这可能不是很有趣。
编辑:如评论中所述。
#define READABLE_PTR(type, ptr) type ptr; \ typedef char ptr ## _READABLE_PTR; #define NON_READABLE_PTR(type, ptr) type ptr; \ #define GET(ptr) \ *ptr; \ {ptr ## _READABLE_PTR \ attempt_to_dereference_non_readable_pointer_ ## ptr;} #define SET(ptr, value) \ *ptr = value; int main(int argc, char *argv[]) { READABLE_PTR(int*, x) NON_READABLE_PTR(int*, y); SET(x, 1); SET(y, 1); int foo = GET(x); int bar = GET(y); // error }