1.概述

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

详述void及void指针类型的使用方法与技巧。

2.void的含义 
void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。

void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变量,让我们试着来定义:

void a;

这行语句编译时会出错,提示“illegal use of type 'void'”。不过,即使void a的编译不会出错,它也没有任何实际意义。

void真正发挥的作用在于: 
(1) 对函数返回的限定; 
(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 *也可以无需强制类型转换地赋给其它类型的指针。因为“无类型”可以包容“有类型”,而“有类型”则不能包

容“无类型”。道理很简单,我们可以说“男人和女人都是人”,但不能说“人是男人”或者“人是女人”。下面的语句编译出错: 
void *p1; 
int *p2; 
p2 = p1;

提示“'=' : cannot convert from 'void *' to 'int *'”。

3.void的使用

下面给出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函数。

林锐博士《高质量C/C 编程》中提到:“C 语言有很严格的类型安全检查,不允许上述情况(指函数不加类型声明)发生”。可是编译

器并不一定这么认定,譬如在Visual C 6.0中上述add函数的编译无错也无警告且运行正确,所以不能寄希望于编译器会做严格的类型检查。

因此,为了避免混乱,我们在编写C/C 程序时,对于任何函数都必须一个不漏地指定其类型。如果函数没有返回值,一定要声明为void类

型。这既是程序良好可读性的需要,也是编程规范性的要求。另外,加上void类型声明后,也可以发挥代码的“自注释”作用。代码的“自注

释”即代码能自己注释自己。

规则二如果函数无参数,那么应声明其参数为void

在C 语言中声明一个这样的函数: 
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语言中,可以给无参数的函数传送任意类型的参数,但是在C 编译器中编译同样的代码则会出错。在C

中,不能向无参数的函数传送任何参数,出错提示“'fun' : function does not take 1 parameters”。

所以,无论在C还是C 中,若函数不接受任何参数,一定要指明参数为void。

规则三 小心使用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标准。

规则四如果函数的参数可以是任意类型指针,那么应声明其参数为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]; 
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 *类型,标准库函数的编写者是多么地富有学问啊!

规则五 void不能代表一个真实的变量

下面代码都企图让void代表一个真实的变量,因此都是错误的代码: 
void a; //错误 
function(void a); //错误

void体现了一种抽象,这个世界上的变量都是“有类型”的,譬如一个人不是男人就是女人(还有人妖?)。

void的出现只是为了一种抽象的需要,如果你正确地理解了面向对象中“抽象基类”的概念,也很容易理解void数据类型。正如不能给抽

象基类定义一个实例,我们也不能定义一个void(让我们类比的称void为“抽象数据类型”)变量。

void类型及void指针相关推荐

  1. c语言使用node类型指针,C语言利用 void 类型指针实现面向对象类概念与抽象

    不使用C++时,很多C语言新手可能认为C语言缺乏了面向对象和抽象性,事实上,C语言通过某种组合方式,可以间接性的实现面对对象和抽象. 不过多态和继承这种实现,就有点小麻烦,但是依然可以实现. 核心: ...

  2. 关于空指针(指针指向为NULL)和void类型的指针的理解

    正在学C,书上老说空指针,或者说void指针,对于我这样的生手来说,理解非常容易造成混淆,因为void这个单词的意思也是空,到底空指针的意思是指指向地址为空的类型呢,还是指void类型的指针呢 (1) ...

  3. C++ void类型指针的使用

    一般情况下,指针的值只能赋给相同类型的指针.但是有一种特殊的 void类型指针,可以存储任何类型的对象地址,就是说任何类型的指针都可以赋值给void类型的指针变量.经过使用类型显示转换,通过void类 ...

  4. void 类型的指针

    void指针是空类型的指针,也称为无类型的指针,它不指向任何类型,即它仅仅是个地址.因此void指针不能进行指针运算,也不能取其所指向的数据的值 只有将void指针跟其他类型的指针相关联,才能使用他, ...

  5. 【二级指针--定义、初始化赋值、解引用;特殊指针--空指针、void类型的指针】(学习笔记12--指针下)

    目录 一.二级指针 指针的指针 二级指针的定义 二级指针的初始化与赋值 二级指针的解引用 二级指针与指针数组 main函数的参数 二.特殊指针 空指针 void类型的指针 新星计划第六篇博文,下面是上 ...

  6. void类型指针 指针的各种组合

    void类型指针: 任何指针都可以赋值给void指针 void指针赋值给其它类型指针时都必须经过类型转换 void转换前不能参与指针运算,除非转换 本质:void指针只知道指向变量/对象的起始地址,却 ...

  7. typedef int(init_fnc_t) (void) 和 typedef int(*init_fnc_t) (void)函数类型和函数指针的区别

    转载请注明原地址:http://blog.csdn.net/oyhb_1992/article/details/76975284 typedef int(init_fnc_t) (void)和 typ ...

  8. C 语言编程 — 高级数据类型 — void 类型

    目录 文章目录 目录 前文列表 void 类型 前文列表 <程序编译流程与 GCC 编译器> <C 语言编程 - 基本语法> <C 语言编程 - 基本数据类型> & ...

  9. void*和void类型

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. void的类型是无类型的数据,void*表示无类型的指针.其中void*可以指向任何数据类型的指针. void类型的用法: (1).voi ...

最新文章

  1. c++监听键盘_你会为颜值买单吗?杜伽fusion复古键盘晒单体验_键盘
  2. linux 删除大量文件
  3. Android ViewModel+liveData+lifecycle+databinding打造MVVM
  4. cordova混合开发流程
  5. python核心编程第三版_《Python核心编程(第3版)》
  6. python随机数列_Python2随机数列生成器简单实例
  7. mysql不记录binlog_MySQL不同的binlog_format会导致哪些SQL不会被记录
  8. [World Final 2016] Branch Assignment
  9. 拓端tecdat|R语言最优聚类数目k改进kmean聚类算法
  10. 《自然语言处理简明教程》读书笔记:前言
  11. 常用图片jpg png jpeg gif等格式介绍
  12. R之相关性的显著性检验
  13. 计算机表格数据怎么样汇总,Excel 中如何汇总相同结构的多个工作表数据
  14. HTML5网页设计制作基础大二dreamweaver作业、使用HTML+CSS技术制作博客网站(5个页面)
  15. 什么是云原生架构?云原生和应用上云不是一码事!
  16. 基于微信在线电子书阅读小程序设计与实现开题答辩PPT
  17. 解读谷歌财报:17亿美元罚款致利润缩减,流量成本激增已迎来下行拐点
  18. Windows中使用curl命令报错curl post [globbing] unmatched close brace/bracket in column 67
  19. Unix环境高级编程-第四章
  20. HTML中tabIndex属性马克 tabIndex='-1'是什么意思

热门文章

  1. 深入解析 Go 中 Slice 底层实现
  2. 如何将应用打包成为 Docker 镜像?
  3. Ribbon负载均衡原理,Feign是如何整合Ribbon的?
  4. KVM中断虚拟化(一)
  5. 多线程的那点儿事(之数据同步)
  6. Java虚拟机JVM的内存管理
  7. MySQL中EXPLAIN详解
  8. “智慧感控”理念革新医疗管理
  9. datatime,time,string转换和format格式化处理
  10. JavaScript中的call,apply,bind学习总结