我正在编写一个 C 程序,根据环境变量对数组应用不同类型的量化。
问题是,我需要使用相同的函数
void foo(void* ptr, quant_t type, ...)
在 ptr 上执行操作,但我需要事先将其转换为正确的类型。
(quant_t是一个枚举类型对象)
我已经尝试过
void foo(void* ptr, quant_t type, ...){
switch(type){
case UNIF:{
struct unif* my_ptr = (struct unif*) ptr;
break;
}
case KMEANS:{
struct kmeans* my_ptr = (struct kmeans*) ptr;
break;
}...}
my_ptr->a = bar(...);
my_ptr->b = baz(...);
}
但是它不起作用,因为 my_ptr 的声明位于 switch case 的范围内。
所以我尝试做这样的事情:
void foo(void* ptr, quant_t type, ...){
void* my_ptr = NULL;
switch(type){
case UNIF:{
my_ptr = (struct unif*) ptr;
break;
}
case KMEANS:{
my_ptr = (struct kmeans*) ptr;
break;
}...}
my_ptr->a = bar(...);
my_ptr->b = baz(...);
}
但是还是不行。
为了使
->a
工作,编译器必须知道字段相对于指针的位置(除其他外)。该偏移量在 C 中必须恒定。
您可以通过使两种类型与第三种类型兼容并使用第三种类型来实现此目的 (
Base
)。
typedef struct {
A a;
B b;
} Base;
typedef struct {
Base base;
...
} Unif;
typedef struct {
Base base;
...
} Kmeans;
// `base` doesn't need to be the first field of `Unif` and `Kmeans`
// (unless you want to recuperate the original pointer at some point).
void foo( Base *ptr, ... ) {
ptr->a = bar( ... );
ptr->b = baz( ... );
}
Unif *unif = ...;
foo( &unif->base, ... );
Kmeans *kmeans = ...;
foo( &kmeans->base, ... );
它不太安全,但我们也可以这样称呼它:
// `base` must be the first field of `Unif` and `Kmeans`.
void foo( Base *ptr, ... ) {
ptr->a = bar( ... );
ptr->b = baz( ... );
}
Unif *unif = ...;
foo( (Base *)unif, ... );
Kmeans *kmeans = ...;
foo( (Base *)kmeans, ... );
这意味着我们可以进行一些更改以减少调用者所需的代码。
// `base` must be the first field of `Unif` and `Kmeans`.
void foo( void *ptr_, ... ) {
Base *ptr = ptr_;
ptr->a = bar( ... );
ptr->b = baz( ... );
}
Unif *unif = ...;
foo( unif, ... );
Kmeans *kmeans = ...;
foo( kmeans. ... );
最后两个不如原来的安全,因为它们通过隐式和显式强制转换失败了类型检查。