关于数据类型的介绍
char //字符数据类型 1字节
short //短整型 2字节
int //整形 4字节
long //长整型 4字节
long long //更长的整形 8字节
float //单精度浮点数 4字节
double //双精度浮点数 8字节
1.类型的基本归类
1.1整型
char short int long long long
char
因为字符的ASCII值是整型,而字符在内存中存储的是字符的ascll值,所以字符也可以理解为整型
signed char 有符号字符型
unsigned char 无符号字符型
通常定义char时到底是signed char还是unsigned char取决于编译器
在VS中char时signed char
int
signed int 有符号整型
unsigned int 无符号整型
在C语言中规定 int默认为signed int型,
short long和long long也是同理
1.12浮点型
float
double
1.13构造类型
数组类型
结构体类型
枚举类型
·····
1.14指针类型
int* p1;
char *p2;
doule* p3;
void* p4;
1.15空类型
通常用于函数的返回类型,函数的参数,指针类型等
这一章我们主要介绍的是整型和浮点型
2.整型在内存中的存储
2.1原码反码补码
整型和浮点型都可以以二进制的形式在内存中存储,
其中整型以二进制反码的形式在内存中存储
先介绍一下原码 反码 补码
其中在有符号数据中,第一位表示符号位 0表示正数,1表示负数
正数的原码反码补码都相同
而负数的原码反码补码要经过计算
下面以-10举例
2.2unsigned int 和 signed int的区别
继续以-10为例再来讲一下 unsigned int和 int的区别
打印unsigned int要用%u
对于整形来说:数据存放内存中其实存放的是补码。 为什么呢?
1.在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统 一处理;
2.同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程 是相同的,不需要额外的硬件电路。
简单来说就是
1.补码可以将符号位和数值位放在一起计算,
2.CPU只有加法器,而原码和反码的转换都只要进行取反加一,
即用补码在加法器中也可以进行减法运算
2.3大小端的介绍
大小端指的是数据在内存中的存储顺序
大端字节序存储:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址 中;
小端字节序存储:是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地 址中。
由此可见VS编译器采用的是小端字节序存储
练习1:设计一个小程序来判断当前机器的字节序
int main()
{
int a = 1;
char* p = (char*)&a;// int是整型,占四个字节,取出第一个字节看看内容
if (*p == 0) // 如果在内存中为 00 00 00 01 第一个字节存储内容为0 就是大端
{ // 如果在内存中为 01 00 00 00 第一个字节存储内容是1 就是小端
printf("大端\n");//
}
if (*p == 1)
{
printf("小端\n");
}
return 0;
}
练习2:求出输出结果
int main()
{
char a=-1;
signed char b=-1;
unsigned char c=-1;
printf("a=%d,b=%d,c=%d\n",a,b,c);
return 0;
}
练习3:求输出结果
int main()
{
char a = -128;
printf("%u\n", a);
return 0;
}
int mian()
{
char a = 128;
printf("%u\n", a);
return 0;
}
两个结果相同
练习4:求输出结果
int main()
{
int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);
return 0;
}
练习5:求输出结果
int main()
{
unsigned i;
for (i = 9; i >= 0; i--)
{
printf("%u ", i);
}
return 0;
}
练习6:求输出结果
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d\n", strlen(a));
return 0;
}
练习7 :求输出结果
#include <stdio.h>
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
3.浮点型在内存中如何存储
3.1浮点数的存储规则
3.2浮点数在内存中的存储格式
float的存储规则
double类型的存储规则
3.11M的存储
因为M是二进制中所以1<=M<2,M可以写成 1.xxxxxx 的形式,其中xxxxxx表示小数部分。
IEEE 754规定,在计算机内部保存M时,默认这个数的第一位总是1,因此可以被舍去,只保存后面的 xxxxxx部分。
比如保存1.01的时 候,只保存01,等到读取的时候,再把第一位的1加上去。这样做的目的,是节省1位有效数字。以32位 浮点数为例,留给M只有23位, 将第一位的1舍去以后,等于可以保存24位有效数字。
3.22.在存储时E是无符号整数
这意味着,如果E为8位,它的取值范围为0~255;如果E为11位,它的取值范围为0~2047。
但是,我们 知道,科学计数法中的E是可以出 现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数 是127;对于11位的E,这个中间 数是1023。
比如,2^10的E是10,所以保存成32位浮点数时,必须保存成10+127=137,即 10001001。 然后,指数E从内存中取出还可以再分成三种情况:
E不全为0或不全为1 这时,浮点数就采用下面的规则表示,即指数E的计算值减去127(或1023),得到真实值,再将 有效数字M前加上第一位的1。 比如: 0.5(1/2)的二进制形式为0.1,由于规定正数部分必须为1,即将小数点右移1位,则为 1.0*2^(-1),其阶码为-1+127=126,表示为 01111110,而尾数1.0去掉整数部分为0,补齐0到23位00000000000000000000000,则其二进 制表示形式为
E全为0 这时,浮点数的指数E等于1-127(或者1-1023)即为真实值, 有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。这样做是为了表示±0,以及接近于 0的很小的数字。
E全为1 这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s); 好了,关于浮点数的表示规则,就说到这里。
练习1:十进制数字5.5的存储![](https://i-blog.csdnimg.cn/direct/6d82a7db3a65433791d6047999e00a25.png)
练习2:输出结果
int main()
{
int n = 9;
//原码 00000000 00000000 00000000 00001001
//正数,原码反码补码相同
float* pFloat = (float*)&n;//将int型指针强制类型转换成float类型指针
printf("n的值为:%d\n", n);
//在取出时按整型读取
// 00000000 00000000 00000000 00001001
//原码,反码,补码相同,所以为9
printf("*pFloat的值为:%f\n", *pFloat);
//*pFloat在读取时按float类型读取
//也就是说
// S E M
// 0 0000 0000 0000 0000 0000 0000 0001 001
// E=-126
// M=0.0000 0000 0000 0000 0001 001
// (-1)^0 * 0.0000 0000 0000 0000 0001 001 * 2^-126
//但是float只能打印到小数点后6位 所以是 0.000000
*pFloat = 9.0;
//1001.0
// 1.001*2^3
// (-1)^0 ^ 1.001 * 2^3
//1001
//S E M
//0 1000 0010 001 0000 00000000 00000000
//
// 也就是 0100 0001 0001 0000 00000000 00000000
//
printf("num的值为:%d\n", n);
//以整数形式取出 0100 0001 0001 0000 00000000 00000000
// 换算成十进制 1,091,567,616
//
printf("*pFloat的值为:%f\n", *pFloat);//9.000000
return 0;
}