当前位置:网站首页>C语言 void和void *(无类型指针)
C语言 void和void *(无类型指针)
2022-08-02 03:22:00 【a只如初见】
void 关键字
void的字面意思是“无类型”,void *则为“无类型指针”,void *可以指向任何类型的数据。
void几乎只有“注释”和限制程序的作用,因为从来没有人会定义一个void变量,让我们试着来定义:
void a;
这行语句编译时会出错,提示“illegal use of type ‘void’”。不过,即使void a的编译不会出错,它也没有任何实际意义。
void真正发挥的作用在于:
- 对函数返回的限定
当函数不需要返回值时,必须使用void限定。例如:void func(int, int)
- 对函数参数的限定
当函数不允许接受参数时,必须使用void限定。例如:int func(void)
void 指针
void的意思就是“无类型”,void指针则为“无类型指针”,void指针可以指向任何类型的数据。所以void指针一般被称为通用指针或者泛指针,或者叫做万能指针。
void指针使用规范
1、void指针可以指向任意类型的数据,即可用任意数据类型的指针对void指针赋值。例如
int *pint ;
void *pvoid ; //它没有类型,或者说这个类型不能判断出指向对象的长度
pvoid = pint ; //只获得变量/对象地址而不获得大小,但是不能 pint=pvoid;
在C语言中,可以把任何类型的指针(包括函数指针)赋值给void*指针而无须进行强制类型转换。
在C++中,对这个转换做了更严格的限制:只有非常量指针才能赋值给void*指针。
C++示例代码:
const char pp[10] = {
0};
const char* str = "aaa";
void* pv = NULL;
pv = pp;//错误
pv = str;//错误 不能将常量指针赋值给void *指针
2、如果要将pvoid赋给其他类型指针,则需要强制类型转换如:
pint = (int *)pvoid; //转换类型也就是获得指向变量/对象大小
注意:在C++编译器中必须转换 pint = (int*)pvoid 否则报错; 但在C编译器中可以写成 pint = pvoid;
3、void指针在强制转换成具体类型前,不能解引用(即取内容的意思);
*pvoid //错误
要想复引用一个指针,或者使用“->”运算符复引用一部分,都要有对于指针指向的内存的解释规则。
例如,int *p;
那么,当你后面复印用p的时候,编译器就会把从p指向的地址开始的四个字节看作一个整数的补码。
因为void指针只知道指向变量/对象的起始地址,而不知道指向变量/对象的大小(占几个字节)所以无法正确引用
4、void指针不能参与指针运算,除非进行转换。
按照ANSI(AmericanNationalStandardsInstitute)标准,不能对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标准,并提高程序的可移植性,我们可以这样编写实现同样功能的代码:
(type*)vp++; //等价于:vp=vp+sizeof(type) type为任意数据类型
void * pvoid ;
(char*) pvoid++ ; //ANSI:正确;GNU:正确
(char*) pvoid+=1 ; //ANSI:错误;GNU:正确
GNU和ANSI还有一些区别,总体而言,GNU较ANSI更“开放”,提供了对更多语法的支持。但是我们在真实设计时,还是应该尽可能地迎合ANSI标准。
void指针的应用
当进行纯粹的内存操作的时候,或者传递一个指向未定类型的指针时,可以使用void指针;
典型的如内存操作函数memcpy和memset的函数原型分别为:
void * memcpy(void *dest,constvoid * src,size_tlen);
void * memset(void * buffer,intc,size_tnum);
这样,任何类型的指针都可以传入memcpy和memset中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型。
注意memcpy和memset函数返回的也是void*类型。
由于void * 可以和任何指针直接做变换,除了函数指针外,在C编译器下,我们知道malloc函数的返回类型是void*,所以下面2句是等价的
int *p =(int*)malloc(100*sizeof(int));
int *p =malloc(100*sizeof(int));
但在C++编译器下,第二句由于没有强制转换将报错。
参考鸣谢:
https://blog.csdn.net/weixin_30268071/article/details/97432128
https://blog.csdn.net/qq_29924041/article/details/54882135
边栏推荐
- docker 安装 sqlserver中的坑点
- 知识问答与知识会话的区别
- How to check whether a table is locked in mysql
- JVM学习----垃圾回收--G1
- @Autowired与@Resource区别
- [详解C语言]一文带你玩转C语言小游戏---扫雷
- [Basic Tutorial of Remote Control Development 1] Crazy Shell Open Source Formation Drone-GPIO (Remote Control Indicator Light Control)
- @Accessors 注解详解
- MySQL8.0与MySQL5.7差异分析
- SOCKS5
猜你喜欢
化学试剂磷脂-聚乙二醇-羟基,DSPE-PEG-OH,DSPE-PEG-Hydroxyl,MW:5000
通过PS 2021 将网页图标抠下来
Cut out web icons through PS 2021
【装机】老毛桃的安装及使用
Phospholipid-Polyethylene Glycol-Aldehyde DSPE-PEG-Aldehyde DSPE-PEG-CHO MW: 5000
PowerManagerService灭屏超时流程
磷脂-聚乙二醇-叠氮,DSPE-PEG-Azide,DSPE-PEG-N3,MW:5000
DSPE-PEG-DBCO Phospholipid-Polyethylene Glycol-Dibenzocyclooctyne A Linear Heterobifunctional Pegylation Reagent
赶紧进来!!!教你用C语言写三子棋小游戏
Redis安装,基本命令,持久化方式,集群
随机推荐
basic operator
AttributeError: Can't get attribute 'SPPF' on
Redis笔记进阶篇:万字长文-整理Redis,各种知识点,建议收藏
JVM学习----垃圾回收--G1
MySQL删除表数据 MySQL清空表命令 3种方法
Dynamic proxy tool class
「PHP基础知识」空值(null)的使用
getattr()函数解析
解决glob()返回文件排序不一致问题&onnx本地按照安装方法
源码构建LAMP环境-1
MySQL分组后取最大一条数据【最优解】
@Autowired详解[email protected]在static属性上的使用
啃瓜记录第一天
MySQL分页查询的5种方法
Mysql8.0安装教程
【程序人生】做了多年的运维,靠什么转行拿下12K+年终奖的薪资?
离线数仓-用户行为采集
Knowledge Engineering Assignment 2: Introduction to Knowledge Engineering Related Fields
青蛙跳台阶:我如何得知它是一道斐波那契数列题?——应用题破题“三板斧”
Phospholipid-polyethylene glycol-thiol, DSPE-PEG-Thiol, DSPE-PEG-SH, MW: 5000