谈谈数据在内存当中的存储
1. C语言的数据类型分类
整数型: char(1字节),short(2字节),int(4字节),long(4字节--32位/8字节--64字节)
浮点型: float(4字节),double(8字节)
构造类型: 结构体struct,枚举类型enum,联合类型union(自定义类型)
空类型: void
2. 整型在内存当中的存储
原码 反码 补码
二进制表示形式有 原码 反码 补码
int a = 10;
4个字节 32个比特位
00000000 00000000 00000000 00001010 原
00000000 00000000 00000000 00001010 反
00000000 00000000 00000000 00001010 补
int b = -10;
对于负数来说 反码为原码按位取反 补码为反码+1
原码求补码 补码求原码 都可以通过取反+1进行转换
10000000 00000000 00000000 00001010 原
11111111 11111111 11111111 11110101 反
11111111 11111111 11111111 11110110 补
内存当中0xff ff ff f6 小端法存储(低位存在低地址 高位存在高地址)
使用补码可以将符号位和数值位统一进行处理 最高位是负值相加即得到最后的实际数据:
对于补码的值 最高位看为负权重 其他位正权重 这样即可统一计算正数与负数(csapp第二章)
原码计算是错误的 补码计算才是正确的 如果按照原码进行计算与求值 则最后的结果应该是-2 显然与现实不符
1+(-1)
00000000 00000000 000000000 00000001//1
11111111 11111111 11111111 11111111//-1
00000000 00000000 00000000 00000000//0
大端 小端法存储数据
0x 11 22 33 44 大端字节序存储
0x 44 33 22 11 小端字节序存储
-
字节序 - 是以字节为单位讨论存储顺序
-
小端字节序存储 把一个数据的低位字节的内容存放在低地址处(常见x86小型机用的都是小端法存储数据)
-
大端字节序存储 把一个数据的低位字节的内容存放在高地址处(ARM大型机)
百度2015面试题:
请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。(10分)
小端字节序: 数据的低位字节存储在低地址处 高位字节存储在高地址处
思路:
-
自己的思路:
通过一个值0x11223344 存储为int变量 再创建一个字符数组char[4] 用一个字符指针char* 指向int变量 逐个字节将内容放入字符数组当中 最终检验字符数组的首元素是否为0x44 如果是 就为小端法 如果不是 那么就是大端法
-
优秀思路:
直接用一个最简单的值0x00000001 int变量 用char* 指向这个变量 解引用得到最低的一个字节 如果这个字节是内容为1 那么就是小端法 如果不是 那么就是大端法 (代码实现起来更简单)
代码:
int check_sys2()
{
//更简单的一个方式
int a = 1;
//对比第一个字节的内容就可以了 如果第一个字节是1 就是小端 如果第一个字节是0 那就是大端
char firstByte = *(char*)&a; //指定引用一个字节的内容 用char*强制类型转换
if (firstByte) return 1;
else return 0;
}
//自己实现的代码
void check_sys()
{
//百度面试题: 讲解一下什么是大端和小端存储 -- 小端 低位字节放在低地址处
//设计一个程序来说明当前机器是大端还是小端
int t = 0x11223344;
char arr[4];
char* p = &t;
for (int i = 0; i < 4; i++)
{
arr[i] = *(p + i);
//地址值占位符要用%p
printf("char arr[%d],地址:%p,值为%x\n", i, p + i, arr[i]);
}
if (arr[3] == 0x44) printf("当前机器是大端法进行数据存储");
else if (arr[3] == 0x11) printf("当前机器是小端法进行数据存储");
//char arr[0], 地址:273fa08, 值为44
//char arr[1], 地址:273fa09, 值为33
//char arr[2], 地址:273fa0a, 值为22
//char arr[3], 地址:273fa0b, 值为11
}
整数类型中 默认为有符号 前面加上unsigned关键字才为无符号
有符号 符号位+数值位 无符号 全部为数值位
10000000 被定义为-128 为 -127-1
有符号char -128~127
无符号char 0~255
考察: 数据的无意溢出造成意外的输出结果
10000000 00000000 00000000 00010100
11111111 11111111 11111111 11101011
11111111 11111111 11111111 111101100//-20补码
00000000 00000000 00000000 000001010//10补码
11111111 11111111 11111111 111110110//相加结果的补码形式
10000000000000000000000000001010//-10
3.浮点数在内存当中的存储
浮点数 就是数学中的小数 123.45-->12.345* 10^1-->1.2345* 10^2 小数点可以浮动 就是浮点数
整型家族的类型表示范围 limits.h
浮点数: float.h
浮点数存储的规则 :IEEE754
S: 符号位 0表示正数 1表示负数 1位
E: 科学技术法的2的指数部分 8位
在内存当中的指数部分表示需要 真值+127(bias) bias的计算公式为2^(E的位数-1)-1 这是为了兼顾指数部分出现负数的情况
指数位全为0的情况 表示极小的数 此时M为0.xxxx 指数部分为-127
指数为全为1的情况 表示极大的数 此时指数部分为128 2^128
其他情况正常计算即可 E-127得到真实的指数
M:
一个例子:
int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}
输出的结果为:
解释:
首先是创建一个int类型的变量 值为9
在内存当中为:
00000000 00000000 00000000 00001001
0 00000000 00000000000000000001001 //E全为0 %.f的精度只到小数点后六位 无法表示 所以为0
如果按照float类型存入9.0
那么在内存当中的存储形式为:
0 10000010 00100000000000000000000
01000001000100000000000000000000//如果按照整数的规则解引用 是一个很大的值 1,091,567,616