许多初学者对C中的void 和void 的指针类型不是很了解。因此常常在使用上出现一些错误,本文将告诉大家关于void 和void 指针类型的使用方法及技巧。

1、首先,我们来说说void 的含义:

void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。 
void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变量,让我们试着来定义: 
void a; 
这行语句编译时会出错,提示“illegal use of type ’void’”。不过,即使void a的编译不会出错,它也没有任何实际意义。 
1.1.void真正发挥的作用在于: 
(1) 对函数返回的限定; 
(2) 对函数参数的限定。 
2、众所周知,如果指针p1和p2的类型相同,那么我们可以直接在p1和p2间互相赋值;如果p1和p2指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的指针类型转换为左边指针的类型。 例如:
    
float *p1;
int *p2;
p1 = p2;
其中p1 = p2语句会编译出错,提示“’=’ :cannot convert from ’int *’ to ’float *’”,必须改为: 
p1 = (float *)p2;
而void *则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换: 
void *p1;
int *p2;
p1 = p2;
但这并不意味着,void *也可以无需强制类型转换地赋给其它类型的指针。因为“无类型”可以包容“有类型”,而“有类型”则不能包容“无类型”。呵呵,这个道理蛮简单,我们可以说“男人和女人都是人”,但不能说“人是男人”或者“人是女人”。下面的语句编译出错: 
int *p2;
p2 = p1;
提示“’=’ :cannot convert from ’void *’ to ’int *’”。

3、然后,我们来说一说void 的使用。
3.1.下面给出了void关键字的使用规则: 
规则一 :如果函数没有返回值,那么应声明为void类型 。
在C语言中,凡不加返回值类型限定的函数,就会被编译器作为返回整型值处理。但是许多程序员却误以为其为void类型。例如: 
add ( int a, int b ) 

return a + b;

int main(int argc, char* argv[]) 

printf ( /"2 + 3 = %d/", add ( 2, 3) );

程序运行的结果为输出: 
2 + 3 = 5 
这说明不加返回值说明的函数的确为int函数。
函数不加类型说明是不允许的,有时候编译器会把它当做其他函数,大家在编译的时候还是要注意,譬如在Visual C++6.0中上述add函数的编译无错也无警告且运行正确,所以不能寄希望于编译器会做严格的类型检查。
因此,为了避免混乱,我们在编写C程序时,对于任何函数都必须一个不漏地指定其类型。如果函数没有返回值,一定要声明为void类型。这既是程序良好可读性的需要,也是编程规范性的要求。另外,加上void类型声明后,也可以发挥代码的“自注释”作用。代码的“自注释”即代码能自己注释自己。
3.2.规则二、 如果函数无参数,那么应声明其参数为void 。
我们来看看这个例子
 int function(void) 

  return 1;

则进行下面的调用是不合法的: 
function(2);
因为在C中,函数参数为void的意思是这个函数不接受任何参数。 
我们来看看看在Turbo C 2.0中编译情况: 
#include /"stdio.h/" 
fun() 

  return 1;

main() 

  printf(/"%d/",fun(2));
  getchar();

编译正确且输出1,这说明,在C语言中,可以给无参数的函数传送任意类型的参数,不能向无参数的函数传送任何参数,出错提示“’fun’ : function does not take 1 parameters”。 
所以,C中,若函数不接受任何参数,一定要指明参数为void。 
3.3.规则三 、小心使用void指针类型 。
按照ANSI(American National Standards Institute)标准,不能对void指针进行算法操作,即下列操作都是不合法的: 
void * pvoid;
pvoid++; //ANSI:错误 
pvoid += 1; //ANSI:错误 
//ANSI标准之所以这样认定,是因为它坚持:进行算法操作的指针必须是确定知道其指向数据类型大小的。 
//例如: 
int *pint;
pint++; //ANSI:正确 
pint++的结果是使其增大sizeof(int)。 
但是大名鼎鼎的GNU(GNU’s Not Unix的缩写)则不这么认定,它指定void *的算法操作与char *一致。 
因此下列语句在GNU编译器中皆正确: 
pvoid++;//GNU:正确 
pvoid += 1; //GNU:正确 
pvoid++的执行结果是其增大了1。 
在实际的程序设计中,为迎合ANSI标准,并提高程序的可移植性,我们可以这样编写实现同样功能的代码: 
void * pvoid;
(char *)pvoid++; //ANSI:正确;GNU:正确 
(char *)pvoid += 1;//ANSI:错误;GNU:正确 
GNU和ANSI还有一些区别,总体而言,GNU较ANSI更“开放”,提供了对更多语法的支持。但是我们在真实设计时,还是应该尽可能地迎合ANSI标准。 
3.4.规则四、 如果函数的参数可以是任意类型指针,那么应声明其参数为void 。
典型的如内存操作函数memcpy和memset的函数原型分别为: 
void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
这样,任何类型的指针都可以传入memcpy和memset中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型。如果 memcpy和memset的参数类型不是void *,而是char *,那才叫真的奇怪了!这样的memcpy和memset明显不是一个“纯粹的,脱离低级趣味的”函数! 
下面的代码执行正确: 
示例:memset接受任意类型指针 
int intarray[100];[Page]
memset ( intarray, 0, 100*sizeof(int) ); //将intarray清0 
示例:memcpy接受任意类型指针 
int intarray1[100], intarray2[100];
memcpy ( intarray1, intarray2, 100*sizeof(int) ); //将intarray2拷贝给intarray1 
有趣的是,memcpy和memset函数返回的也是void *类型,标准库函数的编写者是多么地富有学问啊! 
3.5.规则五、 void不能代表一个真实的变量。 
下面代码都企图让void代表一个真实的变量,因此都是错误的代码: 
void a; //错误 
function(void a); //错误 
4、void体现了一种抽象,这个世界上的变量都是“有类型”的,譬如一个人不是男人就是女人。 
void的出现只是为了一种抽象的需要,如果你正确地理解了面向对象中“抽象基类”的概念,也很容易理解void数据类型。正如不能给抽象基类定义一个实例,我们也不能定义一个void(让我们类比的称void为“抽象数据类型”)变量。 
小小的一个void却蕴藏着很丰富的设计哲学,作为一名编程人员,对这些多一点了解必然使我们事半功倍,受益匪浅。

 
 

(七)C语言中的void 和void 指针类型的更多相关文章

  1. c语言中int long float double 等类型所占字节及输出表示(转)

    16位编译器 char :1个字节 char*(即指针变量): 2个字节 short int : 2个字节 int: 2个字节 unsigned int : 2个字节 float: 4个字节 doub ...

  2. [转载]void及void*的深度剖析

    void的含义 void即"无类型",void *则为"无类型指针",可以指向任何数据类型. void指针使用规范 ①void指针可以指向任意类型的数据,亦即可 ...

  3. void和void*

    void的含义 void即“无类型”,void *则为“无类型指针”,可以指向任何数据类型. void指针使用规范①void指针可以指向任意类型的数据,亦即可用任意数据类型的指针对void指针赋值.例 ...

  4. void与void *

    转载:http://blog.csdn.net/geekcome/article/details/6249151 void的含义 void即“无类型”,void *则为“无类型指针”,可以指向任何数据 ...

  5. 【转】 void与void*详解

    void关键字的使用规则: 1. 如果函数没有返回值,那么应声明为void类型: 2. 如果函数无参数,那么应声明其参数为void: 3. 如果函数的参数可以是任意类型指针,那么应声明其参数为void ...

  6. C/C++语言void及void指针深层探索(转)

    转自:http://www.lanou3g.com/blog/sort/SelfiOS/page/78 1.概述 许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一 ...

  7. 【转载】C/C++语言void及void指针深层探索

    C/C++语言void及void指针深层探索 1.概述许多初学者对C/C++语言中的void及void指针类型不甚理解,因此在使用上出现了一些错误.本文将对void关键字的深刻含义进行解说,并详述vo ...

  8. void及void指针含义的深刻解析

    http://blog.csdn.net/geekcome/article/details/6249151 ----------- void的含义 void即“无类型”,void *则为“无类型指针” ...

  9. 不要伤害指针(5)--void和void指针详解

    原文转载地址:http://blog.csdn.net/sunchaoenter/article/details/6587426 增加自己的想法,作为笔记. 1.概述 许多初学者对C/C++语言中的v ...

随机推荐

  1. mysql5.5.x升级到mysql5.6.x

    大概步骤是: 把配置文件添加:skip-grant-tables参数,把basedir升级成新版本,启动mysql,执行命令:mysql_upgrade升级一下字典信息,然后flush privile ...

  2. python 拷贝文件夹下所有的文件到指定文件夹(不包括目录)

    1.随便简单些写了一下.直接粘结代码,只是简单的实现一下,还很多需要完善和扩展的地方,比如忽略掉后缀文件,删除文件 如果排除的某些的话可以用: sourceF.find('.后缀')>0 2.注 ...

  3. Expanding Rods(二分POJ1905)

    Expanding Rods Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 13688   Accepted: 3527 D ...

  4. Poj(2195),最小费用流,SPFA

    题目链接:http://poj.org/problem?id=2195 Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submi ...

  5. 编译android源码官方教程(2)建立编译环境「linux & mac osx」

    https://source.android.com/source/initializing.html Establishing a Build Environment IN THIS DOCUMEN ...

  6. ContentProvider官方教程(3)ContentResolver查询、遍历 示例

    Retrieving Data from the Provider This section describes how to retrieve data from a provider, using ...

  7. 使用mybatis完成通用dao和通用service

    使用mybatis完成通用dao和通用service 概述: 使用通用dao和通用service可以减少代码的开发.可以将常用的增删改查放到通用dao中.对不同的or框架,基本上都有自己的实现如Spr ...

  8. hdu4992 Primitive Roots(所有原根)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4992 题意:给出n,输出n的所有原根. 思路:求出n的一个原根x,那么对于所以的i,i<phi( ...

  9. MySQL(三) —— 约束以及修改数据表

    约束: 1. 约束保证数据的完整性和一致性: 2. 约束分为表级约束和列级约束: 3. 约束类型包括:NOT NULL, PRIMARY KEY, UNIQUE KEY, DEFAULT, FOREI ...

  10. Know How To Use Check Box Mapping Of Other Values Property In Oracle Forms

    Check Box Mapping of Other Values specifies how any fetched or assigned value that is not one of the ...