#include<stdio.h>
#include<stdlib.h>
void function(void *i, void *j);
struct mystruct {
int a;
int b;
} ;
int main()
{
int a = 50;
struct mystruct s ;
s.a = 100;
s.b = 200;
function(&a, &s);
}
void function(void *i, void *j)
{
printf("Integer is %d\n", *i);
printf("Struct member 1 is %d\n", j->a);
printf("Struct member 2 is %d\n", j->b);
}
我上面的代码。在编译时,我得到以下错误,我理解我需要做些什么来修复它们。
voidstartest.c: In function function:
voidstartest.c:27: warning: dereferencing void * pointer
voidstartest.c:27: error: invalid use of void expression
voidstartest.c:28: warning: dereferencing void * pointer
voidstartest.c:28: error: request for member a in something not a structure or union
voidstartest.c:29: warning: dereferencing void * pointer
voidstartest.c:29: error: request for member b in something not a structure or union
以下是修复错误所需要做的事情:
printf("Integer is %d\n", *(int*)i);
printf("Struct member 1 is %d\n", ((struct mystruct *)j)->a);
printf("Struct member 2 is %d\n", ((struct mystruct *)j)->b);
问题:
如果我必须按照上面描述的方式修复错误并不意味着我必须知道我提前发送给函数的指针类型?我发现这是一个非常严格的要求。不是吗?
某些库函数的形式参数为void *(如qsort)。他们的实现如何知道指针的正确类型是什么,以便他们可以取消引用它以处理实际数据(它指向)?
答案 0 :(得分:5)
是。这意味着您无法以类型无关的方式编写函数,因此需要重新考虑您的设计。使用void*
时,通常会编写模板函数,并向用户询问函数指针,这些函数指向了解类型并执行基本操作的函数。
他们的实施没有。他们还会按照我上面描述的相同方式询问函数指针或大小参数。
答案 1 :(得分:5)
某些库函数的形式参数为void *(如qsort)。他们的实现如何知道指针的正确类型是什么,以便他们可以取消引用它以处理实际数据(它指向)?
因为你还提供了一个比较函数,它接受两个void指针并返回比较结果:
void qsort(void *base, size_t nmemb, size_t size,
int(*compar)(const void *, const void *));
在该函数中,您可以将void指针强制转换为指向数组元素的实际类型的指针,然后执行您想要的任何操作
int compare_your_structs(const void *first, const void *second)
{
const struct mystruct *first_struct = (struct mystruct *)first;
const struct mystruct *second_struct = (struct mystruct *)second;
/* sort by the "a" field only */
return first_struct->a - second_struct->a;
}
答案 2 :(得分:1)
C是静态类型的。 C程序通常不能在运行时推断出指针指向的对象的类型,无论它是void指针还是其他类型的指针。并且它相信你不要通过将指针指向与自己声明的类型不同类型的对象来滥用指针。动态类型语言通常会产生额外功能的开销。
qsort
不需要知道其void指针参数指向的对象的类型。它知道它们的大小,并提供了一个比较函数,该函数应该被编写以比较相关类型的对象。
答案 3 :(得分:0)
库函数可以处理void*
许多不同的方式。例如,qsort
要求用户提供一个函数指针,该指针是为特定类型编写的。这样,用户只需知道类型,但qsort
无需此信息即可运行。
其他功能,例如memcpy
,为方便起见,接受void*
。实际上,由于memcpy
是一个逐字节的副本,它将参数转换为char*
,因此它可以在字节级别上工作。
还可以编写一个类似于printf
的函数,它接受一个标识其参数类型的字符串。类似地,va_arg宏(用于处理varargs)需要一个类型参数,例如: va_arg(list, int)
。虽然printf
和va_arg
不适用于void*
(我认为?),但由于va_list
是无类型的,因此它们面临同样的问题。因此,这些概念也可用于在void*
上运行的函数。