C++ - void*

void* 的用法

void可以指向任何类型的地址,但是带类型的指针不能指向void的地址

  • 正常来说如果两个指针类型不一样的话,两个指针变量是不可以直接相等的。例如int* a, float* b,假如令a = b,会直接发生编译错误。
  • 而 void* 指针可以等于任何类型的指针。但是反过来不可以。
  • 也就是说一个有类型的指针不能指向一个 void* 类型的变量(哪怕此时void*变量已经指向了一个有类型的地址)。
    1
    2
    3
    4
    float f = 5.5;
    float* pf = &f;
    void* pv = pf;
    float* pf2 = pv;//编译错误,有类型的指针变量不能指向void*变量

void*指针只有强制类型转换以后才可以正常取值

1
2
3
4
5
6
7
8
9
10
11
12
13
int main(int argc, const char * argv[]) {

float f = 5.5;
float* pf = &f;
void* pv;

pv = pf; //这句是可以的

cout<<*pv<<endl; //编译错误,这样直接对pv取值是错误的
cout<<*(float*)pv<<endl; //强制类型转换后可以取值

return 0;
}
  • 在令pv = pf后,此时pv和pf指向的是同一个地址,值相同,但是两者的类型是不一样的。
  • pf作为浮点型指针,是可以直接取到浮点数的,但是pv必须要强制类型转换以后才可以取值。
  • 也就是说一个void*的指针必须要经过强制类型转换以后才有意义。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int main(int argc, const char * argv[]) {

    float f = 5.5;
    float* pf = &f;
    void* pv;

    pv = pf;

    cout<<*(float*)pv<<endl; //强制类型转换后可以取值,值为5.5
    cout<<*(int*)pv<<endl; //强制类型转换,值为1085276160
    cout<<(int)(*(float*)pv)<<endl;//取值后再次类型转换,值为5

    return 0;
    }
  • 如果把一个指向 float* 的值的 void* 指针,强制转换成 int* 也是不对的。
  • 也就是说地址保存了什么样的变量,就要转化成哪种类型的指针,否则就会出错。

void*指针变量和普通指针一样可以通过等于0或者NULL来初始化,表示一个空指针

1
2
3
4
void* pv = 0;
void* pv2 = NULL;
cout<<pv <<endl; //值为0x0
cout<<pv2<<endl; //值为0x0

当void*指针作为函数的输入和输出时,表示可以接受任意类型的输入指针和输出任意类型的指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void* test(void* a)
{
return a;
}

int main() {

static int a = 5;
int* pi = &a;

cout<<pi<<endl; //值为0x100001060
cout<<test(pi)<<endl; //值为0x100001060
cout<<test((void*)pi)<<endl; //值为0x100001060
}
  • 如果函数的输入类型为void*,在调用时由于是值传递,所以函数实际接收到的应该就是一个地址值。这个值可以是任意类型。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int a = 5;
    int* pi = &a;

    void* test()
    {
    return pi;
    }

    int main() {
    cout<<test()<<endl; //值为0x100001060
    }
  • 输出时同样也是值传递,因此可以输出任意类型指针指向的地址。

总结:

  • void*类型的指针其实本质就是一个过渡型的指针状态,必须要赋予类型(强制类型转换)才能正常使用。
  • 只能单向类型转换。void* 可以转化成其他类型,但是有类型的不能转化成 void*。
  • 在函数调用过程中的使用作为输入输出参数也非常好用,可以灵活使用任意类型的指针,避免只能使用固定类型的指针。