• c++中的void*


    今天看到一段代码,觉得非常有意思。

    void* say_hello(void* args)
    {
        cout << "Hello World!" << endl;
        return 0;
    }

    这里的返回类型竟然是void*。一般来说如果没有返回值,那么写一个void就行了,void*到底是什么样的存在?所以做了一些测试,总结了一些void*指针的用法。

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

    正常来说如果两个指针类型不一样的话,两个指针变量是不可以直接相等的。例如int* a, float* b,假如令a = b,会直接发生编译错误,而void*指针可以等于任何类型的指针。但是反过来不可以,也就是说一个有类型的指针不能指向一个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<<endl;  //编译错误,这样直接对pv取值是错误的
        cout<<*(float*)pv<<endl;  //强制类型转换后可以取值
        
        return 0;
    }

    在令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<<endl;  //强制类型转换后可以取值,值为5.5
        cout<<*(int*)pv<<endl; //强制类型转换,值为1085276160
        cout<<(int)(*(float*)pv)<<endl;//取值后再次类型转换,值为5
        
        return 0;
    }

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

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

        void* pv = 0; 
        void* pv2 = NULL;
        cout<<pv <<endl; //值为0x0
        cout<<pv2<<endl; //值为0x0

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

    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*,在调用时由于是值传递,所以函数实际接收到的应该就是一个地址值。这个值可以是任意类型。

    int a = 5;
    int* pi = &a;
    
    void* test()
    {
        return pi; 
    }
    
    int main() {
        cout<<test()<<endl;        //值为0x100001060
    }

    输出时同样也是值传递,因此可以输出任意类型指针指向的地址。

    再让我们回头看初始的那段函数:

    //返回了一个空指针
    void* say_hello(void* args)
    {
        cout << "Hello World!" << endl;
        return 0;
    }
    
    //没有返回值
    void say_hello(void* args)
    {
        cout << "Hello World!" << endl;
       return;
    }

    其实两个函数实现的内容是一样的。但是void*返回类型的函数返回了一个空指针,而void型没有返回值。

    总结:

    1)void*类型的指针其实本质就是一个过渡型的指针状态,必须要赋予类型(强制类型转换)才能正常使用。

    2)只能单向类型转换。void*可以转化成其他类型,但是有类型的不能转化成void*。

    2)在函数调用过程中的使用作为输入输出参数也非常好用,可以灵活使用任意类型的指针,避免只能使用固定类型的指针。

  • 相关阅读:
    实体类中的date类型问题
    java.sql.SQLException: validateConnection false
    本地计算机的mysql服务启动后停止
    VUE遇到Windows 64-bit with Unsupported runtime (64) For more information on which environments are supported please see
    有关详细信息, 请使用 -Xlint:unchecked 重新编译。
    mysql出错ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061)
    WIN7系统如何在文件列表中显示文件夹后缀
    shell 两类执行方法
    Git 报错 error setting certificate verify locations
    maven打包不同jdk版本的包
  • 原文地址:https://www.cnblogs.com/corineru/p/10836157.html
Copyright © 2020-2023  润新知