持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
前言
在C中,void是一个很重要很常见的关键字,本文就来分享一波笔者对于该关键字的学习心得与经验。
笔者水平有限,难免存在纰漏,欢迎指正交流。
void 关键字
void是否可以定义变量
试试看:
#include <stdio.h>
int main()
{
void a;
return 0;
}
我们在VS下会发现:
也就是不能定义变量。
同时在vs中,sizeof(void)的值为0:
而在Linux中,sizeof(void)的值为1:
那在这一环境下能否用void定义变量呢?
还是不能,编译器依旧理解成空类型,无法定义变量。
为何 void 不能定义变量
定义变量的本质:开辟空间
而void作为空类型,理论上是不应该开辟空间的,因为void本身被编译器解释为空类型,强制性的不允许定义变量,同时不清楚要开辟多大的空间,即使开了空间,也仅仅作为一个占位符看待,有一些其他的特殊意义。
那么void用来干什么的呢?
void作为函数返回类型
在C中可以不写函数返回类型,这时会默认为int类型。但是最好不要不写,不写的话会让人理解起来产生二义性:这货是忘了写返回类型了还是故意不写想用默认的int类型呢。
即使是没有返回值也要写上个void作为占位符,一来是可以告知用户该函数没有返回值,二来是一旦返回了值只要被接收就会报错(void与其他任意类型都不匹配)。
void作为函数形参
在C中,函数定义里面不设计形参时,能够传参吗?
void fun1()
{}
int main()
{
fun1(1, 2, 3, 4);
return 0;
}
可以的,你硬要传参也不会报警告或错误,只是这样的传参没有实际意义。我们知道,形参是实参的一份临时拷贝,也就是说在函数中是形参接收了实参的值,如果不设计形参的话,传参没有被变量接收,也就无法使用传过去的值,因为值确实是传过去了,只不过没有标识符或者对应地址无法访问,也就无法使用,那传了也没啥意义。
而把void放入函数形参列表时,告知编译器和用户该函数不需要传参,如果还是传参的话编译器就会发出警告。不过不同编译平台的行为其实不一定相同,我们这里用的VS就是警告,还是可以运行,而Linux的gcc就直接不给你运行。
void fun2(void)
{}
int main()
{
fun2(1, 2, 3, 4);
return 0;
}
void 指针
void不能定义变量,那么void*呢?
可以。
为什么void可以呢?因为void是指针,是指针,空间大小就能明确出来:
32位平台下占4个字节
64位平台下占8个字节
void* 能够接收任意类型指针也可以被任何类型指针接收:
int main()
{
void *p = NULL;
int *x = NULL;
double *y = NULL;
//虽然类型不同,但是编译器并不报错
p = x;
p = y;
x = p;
return 0;
}
在库和系统接口的设计上,一般是要尽量设计成通用接口,而如果想设计出通用接口,void*就很有用了。
比如:
memset函数的函数原型
void * memset ( void * ptr, int value, size_t num );
以及qsort函数的设计中,对于要比较的数据内容传参用的就是void*类型。
因为用void*
设计的话可以兼容多种类型(void*
可以接受的任意类型指针),具有通用性。
void* 变量可以进行运算吗
VS下
int main()
{
void *p = NULL;
p++; //报错
p += 1; //报错
return 0;
}
因为指针变量进行加减运算操作时需要根据类型确定步长,比如
int a = 10;
int*p = &a;
p++;
因为p是int*类型,所以移动的步长为sizeof(int)也就是4,p++就是p的值增加4。
而void*无法确定步长,所以就无法进行运算操作。
在gcc4.8.5中
int main()
{
void *p = NULL; //NULL在数值层面,就是0
p++; //能通过
printf("%d\n", p); //输出1
p += 1; //能通过
printf("%d\n", p); //输出2
return 0;
}
为什么在不同的平台下,编译器会表现出不同的现象呢?
根本原因是因为使用的C标准扩展的问题。
GNU计划,又称革奴计划,是由Richard Stallman(理查德·斯托曼)在1983年9月27日公开发起的。它的目标是创建一套完全自由的操作系统。它在编写linux的时候自己制作了一个标准成为 GNU C标准。 ANSI 美国国家标准协会,它对C的ANSI C标准后来被国际标准协会接收成为标准C ,所以 ANSI C 和标准C是一个概念,总体来说现在linux也支持标准C。标准C可以跨平台,而GUN C 一般只在linux C下应用。
Linux 上可用的 C 编译器是 GNU C 编译器,它建立在自由软件基金会的编程许可证的基础上,因此可以自由发布。 而GNU C 对标准 C 进行一系列扩展,以增强标准 C 的功能。
一句话,大部分编译器是标准C,而Linux下是扩展C,同时也能保证标准C的运行。
void*指针可以直接解引用吗? 不能,因为void无法解释变量。
以上就是本文全部内容,感谢观看,你的支持就是对我最大的鼓励~