我正在寻找一种只抛弃波动性而不抛弃基础类型的方法。我知道const_cast
在 C++ 中,我想知道在普通的旧 C 中是否有任何等效的方法可以做到这一点。
问题是我们有一些通过易失性指针访问的共享内存数据库,还有一个使用非易失性指针的 B-tree 库。(在查找过程中树将被锁定,因此编译器不必担心 B 树库中的易变性)。
我们还有大量自动生成的代码将两者联系起来,并从指针中丢弃易失性。不幸的是,今天有人在数据库中使用错误的结构定义了树节点,并且自动生成的转换完全隐藏了编译器的问题。
这有点棘手,但如果你只想从指针类型转换为指针类型,你可以在这里得到预处理器来帮助你。
#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) }
这里的基本技巧是我们在 from Bar
toFoo
中强制分配cv_cast
from Bar*
to Foo*
。这是在,
. 当且仅当您转换不兼容的指针类型时,它才会触发错误。
但是,请注意,cv_cast
指向无效位置(例如NULL
)的 ing 指针将导致段错误。
注意:作为参考(在评论中),这篇文章nullfn
之前使用了一个不必要的辅助函数。有兴趣的可以在历史上查一下。
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... */
这个宏根本不添加任何类型安全性。但至少它让程序员意识到可能存在危险的类型转换,希望让他们在编写错误之前三思而后行。说明为什么在特定情况下这样做是安全的,也是一种很好的做法。
但是,清除所有不正确的强制转换的唯一真正严肃的方法是首先将编译器警告调到最大。在多个编译器上编译它。然后还通过静态分析工具运行代码,该工具专用于发现编译器可以随意忽略的内容。