数据类型专题
一、数据类型的概述
1.1 数据类型
1、基本类型
- 字符型(char)
- 整型(int)
- 实型
- 单精度(float)
- 双精度(double)
- 枚举类型(enum)
2、构造类型 - 数组类型([ ])
- 结构体类型(struct)
- 共用体类型(union)
3、指针类型
4、空类型(void)
1.2 整型数据类型
int main()
{
//有符号类型 signed
char; signed char; // 1byte
short; signed short; // 2byte
int; signed int; // 4byte
long int; signed long int; // 4byte
long long; signed long long; // 8byte
//无符号类型 unsigned
unsigned char; // 1byte
unsigned short; // 2byte
unsigned int; // 4byte
unsigned long int; // 4byte
unsigned long long; // 8byte
//浮点数
float; // 4byte
double; // 8byte
long double; // 8byte 12byte 16byte
//布尔类型
bool; // 1byte
//空类型
void; //不能定义变量,但可以定义指针
return 0;
对于整型,要区分有符号数和无符号数,默认情况下都是有符号数。浮点数本身是具有符号的。
1.3 数据的存储方式
如图中展示的,高位数存放在高地址,低位数存放在低地址,我们称这种存放形式为小端存放
那么,我们如何检测大小端存储?
方法一:直接用指针指向内存空间,然后读取内存空间的值。
我们用char类型指针,指向这块内存,然后读取内存,如果读的值是1,那就是小段存放,如果读的值是0,那么就是大段存放。
#include<stdio.h>
int main()
{
short sa = 0x0001;
char *cp = (char*)&sa;
if(*cp==1)
{
printf("小段\n");
}else{
printf("大端\n");
}
return 0;
}
上面的方法,前提是要对内存的分布情况比较熟悉
方法二:联合体
#include<stdio.h>
union Node
{
short sa;
char ch[2];
};
int main()
{
Node x;
x.sa=0x0001;
if(x.ch[0]==1)
{
printf("小段\n");
}
else
{
printf("大端\n");
}
}
1.4 计算机存储整型数据是以补码存储
计算机存储整型数据是以补码存放的,
对于正数来说,正数的原码=反码=补码;
对于负数来说,负数的反码是负数原码的符号位不变,其余位0变1、1变0。负数的补码是负数的反码+1;对于负数来说,负数的原码等于补码求反+1。
1.5 char,signed char 和 unsigned char类型的表示范围
-128的补码是1000 0000,最高位的1,即表示符号位,也表示数值位
1.6 数值类型的转换(扩充)
int main()
{
char a=5;
char b=-5;
int x=a;
int y=b;
unsigned int z=b;
printf("x=%d y=%d z=%d",x,y,z);
printf("x=%x y=%x z=%x",x,y,z);
return 0;
}
打印结果:
根据上面的实列,可以得出表示范围小的整型变量赋值给表示范围大的整型变量的扩充方式:
- 如果是有符号数,则填充符号位的值
- 如果是无符号数,则填充0
1.7 整型数值的转换(切片或截取)
上面,将整型变量赋值给短整型以及char类型,由于short类型占2个btye所以在赋值的过程中发生了切片与截取现象,将56A8切给了a,同理将A8切给了b。
因此,可以得出一个结论,将表示范围小的整型变量赋值给表示范围大的整型变量的时候,会发生扩充的现象;将表示范围大的整型变量赋值给表示范围小的整型变量的时候,会发生切片与截取现象。
2.1 算术类型转换和赋值类型转换
1、所谓类型相容,指的就是类型不同但系统可以自动进行转换。
a,只针对基本数据类型,char,short.int ,long int, long long ,unsigned char,unsigned short, unsigned int,unsigned long int; unsigned long long , float; double类型。
b.指针,数组,结构体类型,联合体类型,枚举类型,不具此性质。
2不同类型数据的混合运算
- 在运算过程中,当某个二元运算符两边的操作数类型不同但属于类型相容时,系统先将精度低的操作数变换到与另一操作数精度相同,而后再进行运算。
- 赋值类型转换,当赋值号的左值和右值数据类型不一致但属于类型相容时,由系统自动进行类型转换。数据类型转换在∈C语言的表达式中,准许对不同类型的数值进行某一操作或混合运算。当不同类型的数据进行操作时,应当首先将其转换成相同的数据类型,然后进行操作。
数据类型转换有两种形式,即隐式类型转换和显示类型转换。 - 所谓隐式类型转换就是在编译时由编译器按照一定规则自动完成,而不需人为干预。因此,在表达式中如果1有不同类型的数据参与同一运算时,编译器就在编译时自动按照规定的规则将其转换为相同的数据类型。
- C语言规定的转换规则是由低级向高级转换。例如,如果一个操作符带有两个类型不同的操作数时,那么在操作之前行先将较低的类型转换为较高的类型,然后进行运算,运算结果是较高的类型。
- e.所谓低级是指表示数值范围小或精度低,高级是指表示范围大或精度高,如char 比 int 表示范围小;float比double的精度低
这里我们只谈论隐式转换。
2.2 隐式转换
int main()
{
char a=100;
char b=200;
char c=a+b;
printf("%d %d\n",c,a+b);
unsigned char x=100;
unsigned char y=200;
unsigned char z=x+y;
printf("%d %d\n",z,x+y);
return 0;
}
相加,要将其扩充成整型,在这里我扩充成短整型(端整型和整型都可以),进行扩充之后,相加生成一个进位位,这个进位位并没有纳入短整型的范围,不在我们的16位范围之内,又因为将结果给char类型的c变量,所以发生截取,截取低8位给c,所以最终的结果都为44。
通过上面的一个实例,我们可以看出一个非常重要的知识点:
在扩充的过程中:
如果是有符号值,则在扩充的过程中填充符号位上的值
如果是无符号值,则在扩充 的过程中填充0
int main()
{
char c = 128;
unsigned char uc = 128;
unsigned short us = 0;
us = c + uc;
printf("%x\n", us);
us = (unsigned char)c + uc;
printf("%x\n",us);
us = c + (char)uc;
printf("%x\n", us);
us = (unsigned short)c + uc;
printf("%x\n", us);
return 0;
}
c在以下四种情况下会进行隐式转换:
- 算术运算式中,低类型能够转换为高类型
- 赋值表达式中,右边表达式的值自动隐式转化为左边变量的类型,并赋值给他
- 函数调用中参数传递时,系统隐式地将实参转换为形参的类型后,赋给形参
- 函数有返回值时,系统将隐式地将返回表达式类型转换为返回值类型,赋值给调用函数
tip
指针的强转:值不变,但是对内存的解释方式发生转变
cp与ip不能进行隐式转换的原因是:
当把ip的地址给cp,cp也指向ip所指向的空间,但是对*cp解释的时候,解释的是1字节,cp与ip当中的值没有发生转变,发生改变的只是对内存的解析情况,因此,指针在进行隐式转换过程中,要进行强转,将两个指针转换成同一类型。