【转】void及void指针含义的深切解析

    添加时间:2013-5-25 点击量:

    void的含义


    void即“无类型”,void则为“无类型指针”,可以指向任何数据类型。

    void
    指针应用规范
    ①void
    指针可以指向随便率性类型的数据,亦即可用随便率性数据类型的指针对void指针赋值。例如:
    intpint;
    void pvoid;
    pvoid = pint; / 
    不过不克不及 pint= pvoid; /
    若是要将pvoid赋给其他类型指针,则须要强迫类型转换如:pint= (int )pvoid;

    ANSIC标准中,不容许对void指针进行算术运算如pvoid++pvoid+=1等,而在GNU中则容许,因为在缺省景象下,GNU认为voidchar一样。sizeof(pvoid )== sizeof( char).

    void
    的感化
    对函数返回的限制。
    对函数参数的限制。
    当函数不须要返回值时,必须应用void限制。例如: voidfunc(int, int);
    当函数不容许接管参数时,必须应用void限制。例如: intfunc(void)

    因为void指针可以指向随便率性类型的数据,亦即可用随便率性数据类型的指针对void指针赋值,是以还可以用void指针来作为函数形参,如许函数就可以接管随便率性数据类型的指针作为参数。例如:
    void memcpy( void dest, const void src, size_t len );
    void memset( void buffer, int c, size_t num);

    ------------------------------------------------------------------------------



    1. 综述



    很多初学者对C/C++说话中的voidvoid指针类型不甚懂得,是以在应用上呈现了一些错误。本文将对void关键字的深切含义进行申明注解,并胪陈voidvoid指针类型的应用办法与技能。


    2.void的含义



      void的字面意思是“无类型”,void则为“无类型指针”,void可以指向任何类型的数据。void几乎只有“注释”和限制法度的感化,因为从来没有人会定义一个void变量,让我们试着来定义:
    voida;
      这行语句编译时会失足,提示“illegalu搜刮引擎优化ftype’void’”。不过,即使voida的编译不会失足,它也没有任何实际意义。
      void真正阐扬的感化在于:
      (1)对函数返回的限制;
      (2)对函数参数的限制。
       众所周知,若是指针p1p2的类型雷同,那么我们可以直接在p1p2间互相赋值;若是p1p2指向不合的数据类型,则必须应用强迫类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。
      例如:
    floatp1;
    intp2;
    p1=p2;
      此中p1=p2语句会编译失足,提示“’=’:cannotconvert’int’to’float’”,必须改为:
    p1=(float)p2;
    void则不合,任何类型的指针都可以直接赋值给它,无需进行强迫类型转换:
    voidp1;
    intp2;
    p1=p2;
      但这并不料味着,void也可以无需强迫类型转换地赋给其它类型的指针。因为“无类型”可以包涵“有类型”,而“有类型”则不克不及包涵“无类型”。事理很简单,我们可以说“汉子和女人都是人”,但不克不及说“人是汉子”或者“人是女人”。下面的语句编译失足:
    voidp1;
    intp2;
    p2=p1;




      提示“’=’:cannotconvert’void’to’int’”


    3.void的应用



      下面给出void关键字的应用规矩:
      规矩一若是函数没有返回值,那么回声明为void类型
      在C说话中,凡不加返回值类型限制的函数,就会被编译器作为返回整型值处理惩罚。然则很多法度员却误认为其为void类型。例如:
    add(inta,intb)
    {
    returna+b;
    }
    intmain(intargc,charargv[])
    {
    printf(/2+3=%d/,add(2,3));
    }
      法度运行的成果为输出:
      2+3=5
      这申明不加返回值申明的函数的确为int函数。
      林锐博士《高质量C/C++编程》中提到:“C++说话有很严格的类型安然搜检,不容许上述景象(指函数不加类型声明)产生”。可是编译器并不必然这么认定,譬如在VisualC++6.0中上述add函数的编译无错也无警告且运行正确,所以不克不及寄于编译器会做严格的类型搜检。
      是以,为了避免杂沓,我们在编写C/C++法度时,对于任何函数都必须一个不漏地指定其类型。若是函数没有返回值,必然要声明为void类型。这既是法度杰出可读性的须要,也是编程规范性的请求。别的,加上void类型声明后,也可以阐扬代码的“自注释”感化。代码的“自注释”即代码能本身注释本身。 [Page]
    规矩二若是函数无参数,那么回声明其参数为void
      在C++说话中声明一个如许的函数:
    intfunction(void)
    {
    return1;
    }
      则进行下面的调用是不合法的:
    function(2);
      因为在C++中,函数参数为void的意思是这个函数不接管任何参数。
    我们在TurboC2.0中编译:
    #includestdio.h
    fun()
    {
    return1;
    }
    main()
    {
    printf(/%d/,fun(2));
    getchar();
    }
      编译正确且输出1,这申明,在C说话中,可以给无参数的函数传送随便率性类型的参数,然则在C++编译器中编译同样的代码则会失足。在C++中,不克不及向无参数的函数传送任何参数,失足提示“’fun’:functiondoesnottake1parameters”
      所以,无论在C还是C++中,若函数不接管任何参数,必然要指明参数为void
      规矩三警惕应用void指针类型
      遵守ANSI(AmericanNationalStandardsInstitute)标准,不克不及对void指针进行算法操纵,即下列操纵都是不合法的:
    void pvoid;
    pvoid ++;//ANSI
    :错误
    pvoid += 1;//ANSI
    :错误
    ANSI
    标准之所以如许认定,是因为它对峙:进行算法操纵的指针必须是断定知道其指向数据类型大小的。例如:
    int pint;
    pint ++;//ANSI
    :正确
    pint++的成果是使其增大sizeof(int)
    然则大名鼎鼎的GNU(GNU’sNotUnix的缩写则不这么认定,它指定void  的算法操纵与char  一致。
    是以下列语句在GNU编译器中皆正确:
    pvoid ++;//GNU
    :正确
    pvoid += 1;//GNU
    :正确
      pvoid++的履行成果是其增大了1
      在实际的法度设计中,为逢迎ANSI标准,并进步法度的可移植性,我们可以如许编写实现同样功能的代码:
    void pvoid;
    (char)pvoid ++;//ANSI
    :正确;GNU:正确
    (char)pvoid += 1;//ANSI
    :错误;GNU:正确
      GNUANSI还有一些差别,总体而言,GNUANSI更“开放”,供给了对更多语法的支撑。然则我们在真实设计时,还是应当尽可能地逢迎ANSI标准。
      规矩四若是函数的参数可所以随便率性类型指针,那么回声明其参数为void
      典范的如内存操纵函数memcpymemset的函数原型分别为:
    voidmemcpy(voiddest,constvoidsrc,size_tlen);



    voidmemset(voidbuffer,intc,size_tnum);



      如许,任何类型的指针都可以传入memcpymemset中,这也真实地表现了内存操纵函数的意义,因为它操纵的对象仅仅是一片内存,而非论这片内存是什么类型。若是 memcpymemset的参数类型不是void,而是char,那才叫真的新鲜了!如许的memcpymemset明显不是一个“纯粹的,离开初级趣味的”函数!



    下面的代码履行正确:
    //
    示例:memset接管随便率性类型指针
    intintarray[100];[Page]
    memset(intarray,0,100sizeof(int));//
    intarray0
    //
    示例:memcpy接管随便率性类型指针
    intintarray1[100],intarray2[100];
    memcpy(intarray1,intarray2,100sizeof(int));//
    intarray2拷贝给intarray1
      有趣的是,memcpymemset函数返回的也是void类型,标准库函数的编写者是多么地富有学问啊!
      规矩五void不克不及代表一个真实的变量
      下面代码都妄图让void代表一个真实的变量,是以都是错误的代码:
    voida;//
    错误
    function(voida);//
    错误
      void表现了一种抽象,这个世界上的变量都是“有类型”的,譬如一小我不是汉子就是女人(还有人妖?)。
      void的呈现只是为了一种抽象的须要,若是你正确地懂得了面向对象中“抽象基类”的概念,也很轻易懂得void数据类型。正如不克不及给抽象基类定义一个实例,我们也不克不及定义一个void(让我们类比的称void为“抽象数据类型”)变量。


    4.总结



      小小的void储藏着很雄厚的设计哲学,作为一名法度设计人员,对题目进行深一个层次的思虑必定使我们受益匪浅。

    原来,再大的房子,再大的床,没有相爱的人陪伴,都只是冰冷的物质。而如果身边有爱人陪伴,即使房子小,床小,也觉得无关紧要,因为这些物质上面有了爱的温度,成了家的元素。—— 何珞《婚房》#书摘#
    分享到: