【C语言】void 和 void* 类型

简介: 定义 void 类型的变量

一. void 类型

1. 为何不能定义 void 类型的变量

为什么不能定义 void 类型的变量?因为它是空类型,不能够为变量提供空间吗?


定义变量的本质是开辟空间,我们用 sizeof 来计算 void 类型的大小:


在vs2017下,不支持计算 sizeof(void)

在Linux中,sizeof(void)=1

可以看到不同平台下 void 类型的大小是不确定的,在 Linux 平台下 void 类型的大小是一个字节,既然为操作系统其开辟了空间,为什么又不能让它定义变量呢?


考虑 void 作为空类型,理论上是不应该开辟空间的,即使开了空间,也仅仅作为一个占位符看待。所以,既然无法开辟有效存储数据的空间,那么它定义的变量也就无法作为正常变量使用,既然无法使用,编译器干脆强制不让它定义变量。


2. void 作为函数的返回值

void作为函数返回值类型有两个作用:


占位符,明确告知程序员这个函数不需要返回值

告知编译器,这个函数的返回值无法接受


79887e84719e4a1f9f5b12ed9b8c435b.png


二. void* 类型

1. 能否定义 void* 类型的指针?

任何平台、任何编译器,都是可以定义 void* 类型的指针变量的。


使用 sizeof 计算 void* 的大小:

7f3a0074f1f743c188e3d77c68638936.png



可以发现 void* 的大小和其他类型指针变量的大小一样,都是4个字节。


2. 2. void* 类型指针的使用场景

void* 类型的地址可以被其他任何类型的指针变量接收(需要强制类型转)

void* 类型的指针变量也可以接收其他任意类型指针变量的值

int main()
{
  void* p = NULL;
  int* x = NULL;
  double* y = NULL;
  // 两种情况都可以编译通过
  // 不会报错误和警告
  x = (int*)p;
  y = (double*)p;
  p = x;
  p = y;
  return 0;
}


通常在库和系统接口的设计上,会尽量把参数和返回值设计成通用接口:


6e8caaee01df459e8a9e31115b051afd.png


3. void* 类型的指针变量能否进行位运算?

看下面一段代码:


int main()
{
  int a = 10;
  void* p = &a;
  printf("%p\n", p);
  ++p;
  printf("%p\n", p);
  return 0;
}


同一段代码对比两个平台的执行结果:


vs2017:编译不通过,报错"void*":未知的大小

Linux:编译通过,结果输出:0x7fff4bf2f634 0x7fff4bf2f635,结合前面在Linux中计算 sizeof(void) = 1,所以 void* 类型的指针变量的值自增1,会是的地址的值加1。

造成如上结果的原因:两个平台支持的标准有差异


GNU计划,又称革奴计划,是由Richard stallman(理查德·斯托曼)在1983年9月27日公开发起的。它的目标是创建一套完全自由的操作系统。它在编写1inux的时候自己制作了一个标准成为GNU c标准。ANSI美国国家标准协会,它对c做的标准ANSI c标准后来被国际标准协会接收成为标准c所以ANSI C和标准c是一个概念,总体来说现在1inux也支持标准c,以后标准c可以跨平台,而GUN c一般只在linux c下应用。–来自百度

Linux 上可用的c编译器是GNU c编译器,它建立在自由软件基金会的编程许可证的基础上,因此可以自由发布。GNUC对标准C进行一系列扩展,以增强标准C的功能。–来自百度


一句话,大部分编译器是标准C,而Linux下是扩展C,Linux平台也能保证标准c的运行。


4. void* 类型的指针变量可以直接解引用吗?

结果测试不论是在 vs2017 下,还是在 Linux 下都不行。


相关文章
|
6月前
|
存储 数据处理 C语言
C语言类型的变量
C语言类型的变量
59 1
|
6月前
|
存储 编译器 C语言
【C语言】判断字符类型的三种方法
【C语言】判断字符类型的三种方法
446 0
|
6月前
|
存储 C语言
C语言变量类型
C语言变量类型
|
6月前
|
存储 编译器 C语言
c语言中char的作用类型
c语言中char的作用类型
214 0
|
1月前
|
存储 编译器 C语言
C语言:数组名作为类型、作为地址、对数组名取地址的区别
在C语言中,数组名可以作为类型、地址和取地址使用。数组名本身代表数组的首地址,作为地址时可以直接使用;作为类型时,用于声明指针或函数参数;取地址时,使用取地址符 (&),得到的是整个数组的地址,类型为指向该类型的指针。
|
1月前
|
C语言 C++
【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)
【C语言】指针篇-一篇搞定不同类型指针变量-必读指南(3/5)
|
2月前
|
存储 缓存 程序员
c语言的存储类型-存储类
本文详细介绍了C语言中的存储类型及其分类,包括基本类型(如整型、浮点型)和复合类型(如数组、结构体)。重点讲解了不同存储类别(`auto`、`static`、`register`、`extern`、`typedef`、`volatile`、`const`)的特点及应用场景,并展示了C11/C99引入的新关键字(如`_Alignas`、`_Atomic`等)。通过示例代码解释了每个存储类别的具体用法,帮助读者更好地理解和运用这些概念。
|
3月前
|
测试技术 C语言
C语言中的void函数
C语言中的void函数
175 1
|
3月前
|
存储 自然语言处理 编译器
C语言中的char类型
C语言中的char类型
242 1
|
3月前
|
算法 编译器 API
C语言中的longdouble类型
C语言中的longdouble类型