void* say_hello(void* args)
{
cout << "Hello World!" << endl;
return 0;
}
void你经常看见,但是void*你能说出它具体什么意思吗?
我们知道,C++是个强类型语言,指针类型的大小是相同的,即int*的大小与long long*的大小是相同的
sizeof(int*) == sizeof(long long*)
那既然大家都是指针类型,为什么还要分那么多的类别呢?换句话说*号前面的int与longlong这种具体类型的作用是什么呢?且看下面这张图:
在执行+1时,不同类型的指针移动的“距离”不同。如果我们在前面规定了它的类型。那就相当于决定了它的“跳跃力”。“跳跃力”就比如说上面图中int跳了4个字节,但是double跳了8个字节。
基于这样的理解,现在可以对void *下定义了:void * 是一个跳跃力未定的指针
这就是它的神奇之处了,我们可以自己控制在需要的时候将它实现为需要的类型。这样的好处是:编程时候节约代码,实现泛型编程。
1️⃣:void*可以指向任何类型数据的地址,但是带类型的指针不能随意指向void*的地址:
float f = 5.5;
float* pf = &f;
void* pv = pf;
float* pf2 = pv;//编译错误,有类型的指针变量不能指向void*变量
2️⃣:void*指针只有强制类型转换以后才可以正常取值:
int main(int argc, const char * argv[]) {
float f = 5.5;
float* pf = &f;
void* pv;
pv = pf; //这句是可以的
cout<<*pv<
在令pv = pf后,此时pv和pf指向的是同一个地址,值相同,但是两者的类型是不一样的。pf作为浮点型指针,是可以直接取到浮点数的,但是pv必须要强制类型转换以后才可以取值,也就是说一个void*的指针必须要经过强制类型转换以后才有意义。
int main(int argc, const char * argv[]) {
float f = 5.5;
float* pf = &f;
void* pv;
pv = pf;
cout<<*(float*)pv<
如果把一个指向float的值的void指针,强制转换成int*也是不对的。也就是说地址保存了什么样的变量,就要转化成哪种类型的指针,否则就会运行出错。
3️⃣:void*指针变量和普通指针一样可以通过等于0或者NULL来初始化,表示一个空指针
void* pv = 0;
void* pv2 = NULL;
cout<
4️⃣:当void *指针作为函数的输入和输出时,表示可以接受任意类型的输入指针和输出任意类型的指针
void* test(void* a)
{
return a;
}
int main() {
static int a = 5;
int* pi = &a;
cout<
如果函数的输入类型为void*,在调用时由于是值传递,所以函数实际接收到的应该就是一个地址值。这个值可以是任意类型。
int a = 5;
int* pi = &a;
void* test()
{
return pi;
}
int main() {
cout<
再让我们回头看初始的那段函数:
//返回了一个空指针
void* say_hello(void* args)
{
cout << "Hello World!" << endl;
return 0;
}
//没有返回值
void say_hello(void* args)
{
cout << "Hello World!" << endl;
return;
}
其实两个函数实现的内容是一样的。但是void*返回类型的函数返回了一个空指针,而void型没有返回值。
void function(int dataType, void* data) {
// 根据dataType的不同值,进行不同的转换
switch (dataType) {
case 0:
int* a = (int*)data;
case 1:
char* a = (char*)data;
...
}
}
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
memcpy和memset对外接收任何类型的指针,这样是合理并且必要的,因为这是内存操作函数,是对bit进行操作的,考虑数据类型是没有任何意义的。
int *a=NULL;
a=(int *)malloc(sizeof(int));//返回的是void*,所以赋值给其他指针类型要强转一下
同样的,malloc函数只关注你要多大的内存,你需要把它怎么划分是你的事情,但是你需要显式的表明你是怎么划分的。这里语法要求是必须的,void *类型转为其他类型必须强制类型转换。