zoukankan      html  css  js  c++  java
  • C++ void*解惑

    最近遇到void *的问题无法解决,发现再也无法逃避了(以前都是采取悄悄绕过原则),于是我决定直面它。

    在哪遇到了?


    线程创建函数pthread_create()的最后一个参数void *arg,嗯?传地址还是传值?传值好像有警告。

    还有别的出现的地方呢

     

    看memcpy(),返回值和参数都有void *,那又怎么传呢?下面我们首先来说说void *是什么。

    一:void *是什么?

    C语言中,*类型就是指针类型。比如 int *p,double *q,虽然是不一样的指针,但是大小却一样sizeof(p) == sizeof(q),其实很容易理解,因为他们都是同一种类型*类型的。C语言是强类型的语言。对类型的区分十分严格。那这两个有什么不同点吗?有,+1就不同了,看下面的图:


    也就是对于一个指针而言,如果我们在前面规定了它的类型。那就相当于决定了它的“跳跃力”。“跳跃力”就比如说上面图中int跳了4个字节,但是double跳了8个字节。基于这样的理解,我要对void *下定义了:

    void * 是一个跳跃力未定的指针
    二:跳跃力什么时候定?

    这就是它的神奇之处了,我们可以自己控制在需要的时候将它实现为需要的类型。这样的好处是:编程时候节约代码,实现泛型编程。比如我们经常写的排序算法,就可以这么写:


    #include <stdio.h>
    #include <string.h>
    static void Swap(char *vp1, char *vp2, int width)
    {
    char tmp;
    if ( vp1 != vp2 ) {
    while ( width-- ) {
    tmp = *vp1;
    *vp1++ = *vp2;
    *vp2++ = tmp;
    }
    }
    }
    void BubbleSort(void *base, int n, int elem_size,
    int (*compare)( void *, void * ))
    {
    int i, last, end = n - 1;
    char *elem_addr1, *elem_addr2;
    while (end > 0) {
    last = 0;
    for (i = 0; i < end; i++) {
    elem_addr1 = (char *)base + i * elem_size;
    elem_addr2 = (char *)base + (i + 1) * elem_size;
    if (compare( elem_addr1, elem_addr2 ) > 0) {
    Swap(elem_addr1, elem_addr2, elem_size);
    last = i;
    }
    }
    end = last;
    }
    }
    int compare_int(void *elem1, void *elem2)
    {
    return (*(int *)elem1 - *(int *)elem2);
    }
    int compare_double(void *elem1, void *elem2)
    {
    return (*(double *)elem1 > *(double *)elem2) ? 1 : 0;
    }
    int main(int argc, char *argv[])
    {
    int num_int[8] = {8,7,6,5,4,3,2,1};
    double num_double[8] = {8.8,7.7,6.6,5.5,4.4,3.3,2.2,1.1};
    int i;
    BubbleSort(num_int, 8, sizeof(int), compare_int);
    for (i = 0; i < 8; i++) {
    printf("%d ", num_int[i]);
    }
    printf(" ");
    BubbleSort(num_double, 8, sizeof(double), compare_double);
    for (i = 0; i < 8; i++) {
    printf("%.1f ", num_double[i]);
    }
    printf(" ");
    return 0;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57


    上面的compare_int和compare_double就是定它跳跃力的时候。

    三:再来说memcpy

    我们先来看下面这段代 码:

    #include<stdio.h>
    #include<string.h>

    struct stu{
    int id;
    int num;
    };

    #define LEN sizeof(struct stu) /*LEN 为stu的大小*/

    int main(int argc,char *argv[])
    {
    struct stu stu1,stu2;
    stu1.id = 2;
    stu1.num = 3;

    char str[LEN];

    memcpy(str,&stu1,LEN); /*将stu1保存进str*/

    memcpy(&stu2,str,LEN); /*将str转换成stu2*/

    printf("%d %d ",stu2.id,stu2.num); /*访问stu2仍然得到 2 和 3*/
    return 0;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26


    说明:str 是一个char *类型的,但是&stu是一个struct stu *类型的,就像我们前面说的那样,他们的“跳跃力”是不一样的,但是memcpy之所以能将它们都接受,就是因为它的参数是(void *)类型的。在参数传递的时候包容万象,全都接受,这才能体现人家是memcpy()吗,mem是内存,肯定可以不非要按照某种具体类型处理,具体至于还想memcpy的内部怎么处理,看下面:

    http://blog.csdn.net/yangbodong22011/article/details/53227560

    四:总结

    void *是一种指针类型,常用在函数参数、函数返回值中需要兼容不同指针类型的地方。我们可以将别的类型的指针无需强制类型转换的赋值给void *类型。也可以将void *强制类型转换成任何别的指针类型,至于强转的类型是否合理,就需要我们程序员自己控制了。

    #include<stdio.h>

    int main(int argc,char *argv[])
    {
    int a = 2;
    double b = 2.0;
    void *c; //定义void *
    int *p = &a;
    c = p; //将int * 转成void *,
    double *q = (double *)c; //将void *转成double *
    printf("%.f ",*q);

    return 0;
    }

    oid * 为 “不确定类型指针”。
    void *不可以解引用

    (1)void *可以接受任何类型的赋值:
        任何类型的指针都可以直接赋值给void *型指针,无需进行强制类型转换,相当于void *包含了其他类型的指针。

      
    (2)void *可以赋值给任何类型的变量
    但是需要进行强制转换,应为void *的范围较大,所以强制转换,使其进行范围缩小。


    void *主要使用在函数里,可以接受其他类型的指针,让函数使用起来更加便捷。

    void * 1,不能解引用 2,+ - 运算


    结果是不是正确呢?自己试一试吧~

  • 相关阅读:
    idea执行报错NoClassDefFoundError
    git合并几个commit
    jenkins+allure+持续构建+一些配置和遇到的问题
    接口框架坑记录
    jvm-sandbox对运行中的java执行文件做插桩,故障注入
    linux 安装nogui-chrome,构造selenium运行环境
    python之pychram激活码
    python之闭包、装饰器、生成器、反射
    python之 Requests入门到实践
    Python使用xlwt模块 操作Excel文件(转载)
  • 原文地址:https://www.cnblogs.com/tsh292278/p/11289739.html
Copyright © 2011-2022 走看看