我正在寻找一种方法来摆脱波动性,而不会抛弃基础类型。我在C ++中了解const_cast
,我想知道在普通的旧C中是否有相同的方法可以做到这一点。
问题是我们有一些通过易失性指针访问的共享内存数据库,还有一个与非易失性指针一起使用的B树库。 (树在查找期间将被锁定,因此编译器可以不担心B树库中的波动性。)
我们还有一堆自动生成的代码链接两者,并从指针中抛弃volatile。不幸的是,今天有人使用数据库中的错误结构定义了树节点,并且自动生成的转换完全隐藏了编译器的问题。
答案 0 :(得分:1)
这有点棘手但你可以让预处理器在这里帮助你,如果你只想从指针类型转换为指针类型。
#define cv_cast(TYPE,expr) (*((TYPE)(expr)) = *(expr),(TYPE)(expr))
用法:
typedef struct { float f; } Foo; typedef struct { char b; } Bar; void somefunction(void) { Foo f; Bar b; Foo volatile* foov = &f; Foo* foo = 0; Bar* bar = &b; foo = cv_cast(Foo*,foov); // legal (no error, no warning) foov = cv_cast(Foo*,foo); // legal (no error, no warning) foo = cv_cast(Foo*,bar); // illegal (an error) }
这里的基本技巧是我们强制从Bar
到Foo
从cv_cast
到Bar*
强制执行从Foo*
到,
的分配。这是在cv_cast
之后的部分中完成的。当且仅当您要转换不兼容的指针类型时,它才会触发错误。
但请注意,NULL
指向无效位置的指针(例如nullfn
)会导致段错误。
注意:作为参考(在评论中),这篇文章之前使用了辅助函数{{1}},这是不必要的。如果您有兴趣,可以在历史中查找。
答案 1 :(得分:0)
C在类型安全方面并没有太大的作用,标准中没有任何内容可以帮助在编译时发现这些错误。任何明确的类型转换都可能完全抛弃该类型,并留下未定义的行为。
如果你担心这样的类型转换可能会出现,我想你总是可以制作某种宏来使这些错误更难写。
#define PTR_CONST_CAST(type, ptr) ((type*)ptr)
volatile int* const ptr_original;
int* ptr_new;
ptr_new = PTR_CONST_CAST(int, ptr_original);
/* Note: here I am casting away volatile and const because... */
此宏根本不添加任何类型安全性。但至少它让程序员意识到可能存在危险的类型转换,希望在编写错误之前让他们三思而后行。表达为什么在特定情况下这样做是安全的评论也是一种很好的做法。
但是,除去所有不正确的强制转换的唯一真正严肃的方法是首先将编译器警告调整到最大值。在多个编译器上编译它。然后还通过专用于发现编译器可以忽略的内容的static analysis tool来运行代码。