🚀🚀🚀大家觉不错的话,就恳求大家点点关注,点点小爱心,指点指点🚀🚀🚀
目录
🐰基本数据类型和内存映像
🏡前言
数据类型用来定义变量的值的类型,每种数据类型对应特定的字节数。例如在64位操作系统上,int类型的变量拥有4字节的内存单元,double类型占有8字节
🌸基本数据类型
标淮C语言支持的基本(内建)数据类型有 int、 long、float、 double、char、void,以及它们和signed、unsigned、*、&等的组合(有些组合是不支持的,例如void&),标准C++在这些类型的基础上增加了bool 类型,并同时增加了两个内置的符号常量true 和false(关键字)
✈️void类型
void是“空”类型(无值型),意思是这种类型的大小无法确定。显然不存在 void类型的对象,所以你也就不能声明 void 类型的对象或是将sizeof()运算符用于 void类型,C++/C 语言不能对一个大小末知的对象直接操作。void 通常用来定义函数的返回类型、参数列表(无参)或者void 指针,void 指针可以作为通用指针,因为它:可以指向任何类型的对象。
🤔提示
字节是内存编址的最小单位。因为语言必须支持对一个变元(基本类型或复合类型的变量或对象)进行取址运算(&),而且这个地址必须是有效的内存单元的地址,所以最小对象(包括控对象)也至少占据1字节的内存空间。
虽然bool 类型的变量只存在两种可能的值:true 和false,按理说只需要一个bit就可以表示了。但是字节是内存编址的最小单位,而计算机从内存中提取一个变量的值是通过其地址进行的,所以一个bool 变量也占据 1字节内存,即sizeof(bool)等于1,浪费了7bit。
‼️注:标准C语言中没有bool 类型,但是某些实现通过库提供了其映射,并且定义了相应的常量。
‼️注:在标准C中,int 为默认类型,也就是说如果你不明确指定函数的形参类型或函数的返回值类型,则它们的类型为 int。标准C++不支持默认类型,但是在模板中有“默认类型参数”的概念
🐰类型转换
🏡前言
当c程序中某个地方所需要的数据类型并非你虽提供的类型时,通常要进行数据类型转换,这就是c语言强制类型检查机制的具体表现。例如在一个同时出现了不同类型的操作数的复合算数表达式中,一般占用内存较少的类型会隐式地转换为表达式中占用内存最多的操作数类型。c++也是一样,甚至提供了比c更严格的静态类型检查系统。
‼️注:从本质上来说,C++/C 不会直接对两个类型不同的操作数进行运算,如果操作数类型不同,编译器就会试图运用隐式类型转换规则或者按照用户要求进行强制类型转换。类型转换并不是改变原来的类型和值,而是生成了新的临时变元,其类型为目标类型。
🌸隐式转换
✈️定义
所谓的隐式转换,就是编译器在背后帮助程序员做的转换工作,程序员察觉不到。既然是编译器自动进行的,那么这种的类型转换必须具有足够的安全性。如果程序员的确想要做这样的转换,那么需要显示地使用强制类型转换。
✈️基本数据类型的兼容关系
基本数据类型之间存在如下的兼容关系:char is-a int,int is-a long,long is-a float,foat is-a double,并且is-a关系是传递的。
一个低级数据类型对象总是优先转换为能够容纳得下它的最大值的、占用内存最少的高级类型对象。例如 100 这个字面常量(类型为 int)如果转换为 long 型就能满足编译器的要求,那就不会转换为 double 型。比如下面的两个重载函数:
1. void f(long l); 2. void f(double d);
如果存在调用f(100),则必然调用f(long l)而不是f(double d),除非不存在 f(long l)才会连接到 f(double d)。
🤔提示
标准C语言允许任何非 void 类型指针和void 类型指针之间进行直接的相互转换。但在C++中 ,可以把任何类型的指针直接指派给 void 类型指针,因为 void*是一种通用指针;但是不能反过来將 void 类型指针直接指派给任何非 void 类型指针,除非进行强制转换。因此,在C语言环境中我们就可以先把一种具体类型的指针如int*转换为 void*类型,然后再把void* 类型转换为 double*类型,而编译器不会认为这是错误的。 然而这样的做法确实存在着不易察觉的安全问题(内存扩张和截断等),这是标准C语言的一个缺陷。
🌸强制类型转换
✈️引入
基本数据类型的之间的指针转换一般来说必然会造成内存截断或内存访问范围的扩张,除非两种类型具有相同字节大小。例如32位系统中,int,long,float,都是具有4字节的空间,虽然不会造成内存截断或内存扩张,但是它们之间的指针转换改变了编译器对所指向的内存单元的解释方式,因此结果必然是错误的。
例如:
1. Double d=1000.25; 2. Int* pInt=(int*) &d5; 3. Int i4=100; 4. Double* pDbl=(double*)&i4;
从内存的访问角度来说,你通过pInt访问它指向的double类型变量d5是安全的(后面4字节被“截断”了,可访问内存范围缩小),但是其值绝对不会是d5的整数部分1000,而是位于d5开头4字节中的内容,并解释为int类型数,这个数式不可预料的;同样,你通过pDbl访问int类型变量i4,得到的数据不一定是100,况且造成可访问内存的“扩大”。如果你往里面写数据就会产生运行错误,
🤔提示
- 对于基本类型的强制转换一定要区分值的截断于内存截断不同;
- 使用强制转换,必须同时确保内存访问的安全性和转换结果的安全性;
- 需要数据类型转换,请尽量使用显式的数据类型转换,让人们知道发生了什么事,避免编译器进行隐式数据类型转换;
🌸🌸🌸如果大家还有不懂或者建议都可以发在评论区,我们共同探讨,共同学习,共同进步。谢谢大家! 🌸🌸🌸