声明 void 指针以将类型处理推送到下游
Declaring void pointers to push type handling downstream
像下面这样的事情是否常见:
void *x = (void *) "one";
void *y = (void *) 2;
void *z = (void *) NULL;
而不是:
char * x = "one";
int y = 2;
我问这个的原因是能够调用一个可以接受多种类型的函数。例如,在 javascript 中可以使用各种元素的连接,例如 javascript。似乎在某种程度上使用 (void *)
只是表示 "any type".
的一种简单方法
不,因为您不能取消引用 void 指针:您必须知道存储的是什么类型,这会使这个想法变得毫无用处。
您可能正在寻找的是 variant type。
enum type {
CHAR, INT, DOUBLE, STR
};
typedef struct {
union {
char c;
int i;
double d;
char *str;
};
enum type t;
} variant;
void displayGenericObjec(variant v)
{
switch (v.t) {
case CHAR:
putchar(v.c);
break;
case INT:
printf("%d", v.i);
break;
case DOUBLE:
printf("%f", v.d);
break;
case STR:
printf("%s", v.str);
break;
}
}
variant x;
x.t = INT;
x.i = 42;
displayGenericObject(x);
这不是一个非常实用的解决方案,但它适用于只需要几种类型的普通代码。
通常,编写带有任何参数的函数并不是一个好主意。如评论中所述,您失去了编译器提供的类型检查。
但是,在某些情况下您可能需要考虑使用 'void *',这些情况(通常)被认为是可以接受的:(1) 可变参数函数和 (2) 回调。重要的是要强调,如果可能,最好考虑替代实施。
varargs 函数是像 'printf'、'scanf' 等函数,其中函数可以接受可变数量的参数,可能是不同的类型,并且通常会使用来自正确解码其余参数的第一个参数。
回调是其他示例,其中代码有时必须指定将在事件发生时调用的函数。许多框架将要求回调匹配预定义的 "typedef",代码稍后会将参数转换为实际类型。例如,'qsort' 原型需要一个 'compar' 函数,该函数通常定义为采用 'void *',其中实际函数会将参数转换为实际类型。
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
根据历史记录,"C" 的初始版本(有时称为 "K&R C")确实允许在没有形式参数列表的情况下定义函数。实践经验证明,这样做是有风险的、无益的。在那些日子里,您可以在头文件中编写函数,例如:
/* in file.h */
int foo() ;
/* in file.c */
int foo(a)
int a ;
{
}
/* in prog.c */
{
a(5,4,"x") ;
}
像下面这样的事情是否常见:
void *x = (void *) "one";
void *y = (void *) 2;
void *z = (void *) NULL;
而不是:
char * x = "one";
int y = 2;
我问这个的原因是能够调用一个可以接受多种类型的函数。例如,在 javascript 中可以使用各种元素的连接,例如 javascript。似乎在某种程度上使用 (void *)
只是表示 "any type".
不,因为您不能取消引用 void 指针:您必须知道存储的是什么类型,这会使这个想法变得毫无用处。
您可能正在寻找的是 variant type。
enum type {
CHAR, INT, DOUBLE, STR
};
typedef struct {
union {
char c;
int i;
double d;
char *str;
};
enum type t;
} variant;
void displayGenericObjec(variant v)
{
switch (v.t) {
case CHAR:
putchar(v.c);
break;
case INT:
printf("%d", v.i);
break;
case DOUBLE:
printf("%f", v.d);
break;
case STR:
printf("%s", v.str);
break;
}
}
variant x;
x.t = INT;
x.i = 42;
displayGenericObject(x);
这不是一个非常实用的解决方案,但它适用于只需要几种类型的普通代码。
通常,编写带有任何参数的函数并不是一个好主意。如评论中所述,您失去了编译器提供的类型检查。
但是,在某些情况下您可能需要考虑使用 'void *',这些情况(通常)被认为是可以接受的:(1) 可变参数函数和 (2) 回调。重要的是要强调,如果可能,最好考虑替代实施。
varargs 函数是像 'printf'、'scanf' 等函数,其中函数可以接受可变数量的参数,可能是不同的类型,并且通常会使用来自正确解码其余参数的第一个参数。
回调是其他示例,其中代码有时必须指定将在事件发生时调用的函数。许多框架将要求回调匹配预定义的 "typedef",代码稍后会将参数转换为实际类型。例如,'qsort' 原型需要一个 'compar' 函数,该函数通常定义为采用 'void *',其中实际函数会将参数转换为实际类型。
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
根据历史记录,"C" 的初始版本(有时称为 "K&R C")确实允许在没有形式参数列表的情况下定义函数。实践经验证明,这样做是有风险的、无益的。在那些日子里,您可以在头文件中编写函数,例如:
/* in file.h */
int foo() ;
/* in file.c */
int foo(a)
int a ;
{
}
/* in prog.c */
{
a(5,4,"x") ;
}