Void 关键字:
void 的字面意思是“空类型”,void *则为“空类型指针”,void *可以指向任何类型的数据。
众所周知,如果指针p1 和p2 的类型相同,那么我们可以直接在p1 和p2 间互相赋值;
如果p1 和p2 指向不同的数据类型,则必须使用强制类型转换运算符把赋值运算符右边的
指针类型转换为左边指针的类型。
float *p1;
int *p2;
p1 = p2;
其中p1 = p2 语句会编译出错,必须改为:
p1 = (float *)p2;
而void *则不同,任何类型的指针都可以直接赋值给它,无需进行强制类型转换:
void *p1;
int *p2;
p1 = p2;
但这并不意味着,void *也可以无需强制类型转换地赋给其它类型的指针。因为“空类型”可
以包容“有类型”,而“有类型”则不能包容“空类型”
void *p1;
int *p2;
p2 = p1;
这样就会出错。
void 修饰函数返回值和参数
如果函数没有返回值,一定要声明为void 类型。
如果函数无参数,那么应声明其参数为void
int function(void)//有返回值
{
return 1;
}
像这种是不好的
fun()
{
return 1;
}
警告:返回类型默认为 ‘int’
void 指针
不能对void 指针进行算法操作
如:
void * pvoid;
pvoid++; //ANSI:错误
pvoid += 1; //ANSI:错误
进行算法操作的指针必须是确定知道其指
向数据类型大小的。也就是说必须知道内存目的地址的确切值。
例如:
int *pint;
pint++; //ANSI:正确
但是大名鼎鼎的GNU(GNU's Not Unix 的递归缩写)则不这么认定,它指定void *的算法
操作与char *一致。因此下列语句在GNU 编译器中皆正确:
pvoid++; //GNU:正确
pvoid += 1; //GNU:正确
并提高程序的可移植性,我们可以这样编写
实现同样功能的代码:
void * pvoid;
(char *)pvoid++; //ANSI:正确;GNU:正确
(char *)pvoid += 1; //ANSI:错误;GNU:正确
典型的如内存操作函数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_a[100];
memset (IntArray_a, 0, 100*sizeof(int) ); //将IntArray_a 清0
例子:memcpy 接受任意类型指针
int destIntArray_a[100], srcintarray_a[100];
//将srcintarray_a 拷贝给destIntArray_a
memcpy(destIntArray_a, srcintarray_a, 100*sizeof(int) );
有趣的是,memcpy 和memset 函数返回的也是void *类型,标准库函数的编写者都不是一
般人。
void 不能代表一个真实的变量。
因为定义变量时必须分配内存空间,定义void 类型变量,编译器到底分配多大的内存呢。
下面代码都企图让void 代表一个真实的变量,因此都是错误的代码:
void a; //错误
function(void a);//错误
void 体现了一种抽象,这个世界上的变量都是“有类型”的。