C语言中void*详解及应用

2023-11-04

void在英文中作为名词的解释为“空虚;空间;空隙”;而在C语言中,void被翻译为“无类型”,相应的void *为“无类型指针”。void似乎只有“注释”和限制程序的作用,当然,这里的“注释”不是为我们人提供注释,而是为编译器提供一种所谓的注释。

本文地址:http://www.cnblogs.com/archimedes/p/c-void-point.html,转载请注明源地址。

void的作用:
1.对函数返回的限定,这种情况我们比较常见。

2.对函数参数的限定,这种情况也是比较常见的。

一般我们常见的就是这两种情况:

当函数不需要返回值值时,必须使用void限定,这就是我们所说的第一种情况。例如:void func(int a,char *b)。

当函数不允许接受参数时,必须使用void限定,这就是我们所说的第二种情况。例如:int func(void)。

void指针的使用规则:
1.void指针可以指向任意类型的数据,就是说可以用任意类型的指针对void指针对void指针赋值。例如:

  int *a;

  void *p;

  p=a;

 如果要将void指针p赋给其他类型的指针,则需要强制类型转换,就本例而言:a=(int *)p。在内存的分配中我们可以见到void指针使用:内存分配函数malloc函数返回的指针就是void *型,用户在使用这个指针的时候,要进行强制类型转换,也就是显式说明该指针指向的内存中是存放的什么类型的数据(int *)malloc(1024)表示强制规定malloc返回的void*指针指向的内存中存放的是一个个的int型数据。

2.在ANSI C标准中,不允许对void指针进行一些算术运算如p++或p+=1等,因为既然void是无类型,那么每次算术运算我们就不知道该操作几个字节,例如char型操作sizeof(char)字节,而int则要操作sizeof(int)字节。而在GNU中则允许,因为在缺省情况下,GNU 认为void *和char *一样,既然是确定的,当然可以进行一些算术操作,在这里sizeof(*p)==sizeof(char)。

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

void a;

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

众所周知,如果指针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指针类型:

按照ANSI(American National Standards Institute)标准,不能对void指针进行算法操作,即下列操作都是不合法的:

void * pvoid;
pvoid++; //ANSI:错误
pvoid += 1; //ANSI:错误
//ANSI标准之所以这样认定,是因为它坚持:进行算法操作的指针必须是确定知道其指向数据类型大小的。
//例如:
int *pint;
pint++; //ANSI:正确
pint++的结果是使其增大sizeof(int)。
但是GNU则不这么认定,它指定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 *

注:void指针可以任意类型的数据,可以在程序中给我们带来一些好处,函数中形为指针类型时,我们可以将其定义为void指针,这样函数就可以接受任意类型的指针。如:

典型的如内存操作函数memcpy和memset的函数原型分别为:

void * memcpy(void *dest, const void *src, size_t len);
void * memset ( void * buffer, int c, size_t num );
这样,任何类型的指针都可以传入memcpy和memset中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型(参见C语言实现泛型编程)。如果memcpy和memset的参数类型不是void *,而是char *,那才叫真的奇怪了!这样的memcpy和memset明显不是一个“纯粹的,脱离低级趣味的”函数!void的出现只是为了一种抽象的需要,如果你正确地理解了面向对象中“抽象基类”的概念,也很容易理解void数据类型。正如不能给抽象基类定义一个实例,我们也不能定义一个void(让我们类比的称void为“抽象数据类型”)变量。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言中void*详解及应用 的相关文章

随机推荐

  • JS封装计算1~100之间所有整数的总和与平均值

    function getSum var sum 0 for i 0 i lt 100 i sum i console log 1 100所有数和为 sum console log 1 100所有数和的平均值为 sum 100 getSum
  • Intellij idea 导入 jdbc

    第一步 去官网https dev mysql com downloads connector j 下载驱动程序 第二步 解压压缩包 记住路径 第三步 打开你的idea工程 打开Project Structure Modules gt gt
  • RabbitMQ - 死信、TTL原理、延迟队列安装和配置

    目录 一 死信交换机 1 1 什么是死信交换机 1 2 TTL 1 2 1 什么是 TTL 1 2 2 通过 TTL 模拟触发死信 二 延迟队列 2 1 什么是延迟队列 2 2 配置延迟队列插件 2 2 1 延迟队列配置 a 下载镜像 b
  • pyhive报错Could not start SASL: b‘Error in sasl_client_start (-4) SASL(-4)

    python3连接hive 1 安装对应依赖 2 连接hive 3 常见报错 1 安装对应依赖 pip install sasl pip install thrift pip install thrift sasl pip install
  • 快速上手Cruisecontrol

    1 Cruisecontrol的概述 CruiseControl是一种持续集成过程的框架 包括了邮件通知 ant和各种源码控制工具的插件 并提供web接口 用于查看当前和以前的build的结果 2 Cruisecontrol的安装 2 1
  • windows下免费本地部署类ChatGpt的国产ChatGLM-6B

    ChatGLM 6B 是一个开源的 支持中英双语的对话语言模型 基于 General Language Model GLM 架构 具有 62 亿参数 结合模型量化技术 用户可以在消费级的显卡上进行本地部署 INT4 量化级别下最低只需 6G
  • 万字长文,SpringSecurity

    思维导图如下 RBAC权限分析 RBAC 全称为基于角色的权限控制 本段将会从什么是RBAC 模型分类 什么是权限 用户组的使用 实例分析等几个方面阐述RBAC 思维导图 绘制思维导图如下 什么是RBAC RBAC 全称为用户角色权限控制
  • javascript算法之数组反转浅谈

    本文主要介绍了javascript算法之数组反转 文章围绕主题展开详细的内容介绍 具有一定的参考价值 需要的小伙伴可以参考一下 1 数组反转 1 1 leecode题目 旋转数组 给你一个数组 将数组中的元素向右轮转 k 个位置 其中 k
  • Servlet是不是线程安全的?

    首先在servlet中的方法 三个重要方法 1 init 进行资源的加载 2 service 处理请求 根据请求方式 调用doGet或者doPost 3 destroy 进行资源的释放 servlet是单实例的 假如在处理请求时候 多线程访
  • AcWing 104. 货仓选址

    题目 在一条数轴上有 N 家商店 它们的坐标分别为 A1 AN 现在需要在数轴上建立一家货仓 每天清晨 从货仓到每家商店都要运送一车商品 为了提高效率 求把货仓建在何处 可以使得货仓到每家商店的距离之和最小 输入格式 第一行输入整数N 第二
  • windows下访问linux下的文件,【IT之家学院】如何从Win10访问Linux子系统中的文件 - IT之家...

    在19H1 目前处于Insider Preview阶段 预计4月份正式推送 中 微软为适用于Linux的Windows子系统带来了一项有趣的功能 这项功能允许用户从Windows 10访问Linux子系统中的文件 今天的这期教程 我们来讨论
  • AppScan 漏扫工具-保姆及配置使用说明

    本文章仅供学习使用 严禁在未经网站管理员的允许的条件下扫描任何网站 工具的滥用违反国家安全法后果自负 申明 本文实验环境在内网中进行 网站为自己服务器所搭建的sqli labs DVWA master测试网站 1 AppScan安装和基础配
  • 请分别创建出listA、listB、listC,完成以下各题 (1)将listC中的内容添加到listB中: (2)输出listA与listB的交集listD; (3)输出listA与listB的并集...

    答 1 将listC中的内容添加到listB中 将listC中的每一项元素都添加到listB尾部 2 输出listA与listB的交集listD 定义一个空listD 遍历listA中的每个元素 如果listB中有相同的元素 则将该元素加入
  • 爬虫碰到状态码412的解决办法

    爬虫碰到状态码412 近期在使用python的requests库爬取网页时 碰到返回状态码为412的情况 状态码412含义为 Precondition Failed 服务器在验证在请求的头字段中给出先决条件时 没能满足其中的一个或多个 这个
  • Arthas 使用实践

    文章目录 1 Arthas 2 学习总结 2 1 所有环境都在线上 学习时不用自己搭环境 2 2 官方文档 2 3 相关参考博文 2 4 idea arthas 插件 3 各种捣腾 3 1 Arthas 下载使用 3 2 支持管道操作 3
  • 物联网智能病床项目

    目录 第一部分 系统架构 第二部分 MCU工作过程 第三部分 嵌入式操作系统 第一部分 系统架构 总体采用设备端 MCU 医用传感器 通信模组 WiFi 蓝牙 4G 通信端 MQTT协议 应用层服务器组成构建一整套物联网系统 第二部分 MC
  • pytest框架之fixture测试夹具详解

    一 fixture的优势 pytest框架的fixture测试夹具就相当于unittest框架的setup teardown 但相对之下它的功能更加强大和灵活 命名方式灵活 不限于unittest的setup teardown 可以实现数据
  • 14-1_Qt 5.9 C++开发指南_网络编程及主机信息查询_HostInfo

    Qt 网络模块提供了用于编写 TCP IP 客户端和服务器端程序的各种类 如用于 TCP 通信的QTcpSocket 和 QTcpServer 用于 UDP 通信的 QUdpSocket 还有用于实现 HTTP FTP 等普通网络协议的高级
  • Flex4 Error #2032 Stream Error的解决方式

    最近在做一个项目 在程序发布的初期没有发现什么问题 但是有的用户反映看不到站点 并截图Error 2032错误 但是在研发中心测试没有问题 后来通过测试幸运地在一台测试机上发现了这个问题 而同时测试其他9台机器 发现都可以正常显示 而后到网
  • C语言中void*详解及应用

    void在英文中作为名词的解释为 空虚 空间 空隙 而在C语言中 void被翻译为 无类型 相应的void 为 无类型指针 void似乎只有 注释 和限制程序的作用 当然 这里的 注释 不是为我们人提供注释 而是为编译器提供一种所谓的注释