【C语言进阶】数据是如何存储的?
数据的类型本质上就是告知内存该数据的存放多大的空间。
1.整型在内存中如何存储
整型在内存中是以二进制补码的方式进行存储的,这里不懂原反补码的同学可以花5分钟自行学习,这里不再赘述。如下图所示,在vs编译器中使用16进制查看内存中的数据。
看到这里的小伙伴,一定会有疑问,为什么内存中的数据是“倒着存”的?这就引出了接下来要讨论的内容:“大小端”。
1.1 什么是大小端
在整型存储的时候,存储数据有时候会占用多个字节,这就需要讨论存储字节的顺序问题了,这就是所谓的“大小端”问题。
大端存储模式:数据的低位存储在内存的高地址中,数据的高位存储在内存的低地址中。(正着存)
小端存储模式:数据的低位存储在内存的低地址中,数据的高位存储在内存的高地址中。(倒着存)
举个例子:一个16进制的数据0x11223344分别按照大端、小端的方式进行存储,那么内存结构图如下图所示。如果按照大端存储,即“正着存”,其实就是数据的低位存储到内存的高地址;如果按照小端存储,即“倒着存”,其实就是数据的高位存储到内存的高地址。
这样一来,我们可以得到在vs编译器中查看内存的时候,数据为什么是“倒着存”的原因,即此时编译器采用“小端存储”。
大小端的问题只存在于存储两个以及两个字节以上的内容,如果数据的类型为char类型,只有一个字节,那么就不存在字节之间存放顺序的问题了。
1.2 关于大小端的百度面试题(2015年)
请简述大小端字节序的概念;设计程序判断当前机器的大小端
概念问题上面已经说明,这里不再赘述;关于设计程序判断大小端的问题,思路如下:只需要判断数据的第一个字节存放的数据,如果存放的是0那么就是大端存储,如果存放的非0那么就是小端存储。
那么接下来的问题就是如何拿到第一个字节的数据,当&a的时候会拿到a的起始地址,此时解引用只会拿到四个字节存放的数据,因为&a的类型是int*,所以需要先强制类型转换为char*再进行解引用,这样一来就会拿到第一个字节存放的数据。
#include<stdio.h>int main()
{int a = 1;if(*(char*)&a == 0){printf("此机器是大端存储");}else{printf("此机器是小端存储");}return 0;
}
1.3 数据存储的一些练习
1.3.1 求输出结果
分析:char类型占用1个字节,这时候存储分为有符号存储和无符号存储;我们先来看有符号存储。有符号存储最高位不能用来存储数据只用来代表符号,如下图所示:
由于正数三码合一,所以我们可以直接读出来正数的取值范围为:0-127,负数的存储是以补码的方式存储,想要获得负数的原码,只需要“取反+1”,11111111的原码那就是10000001即-1;依以此类推10000001的原码是11111111就是-127,这里需要注意的一点是:10000000是一个特殊值,不能按照原码补码的规律计算,这里人为定义它为-128。
这样一来,有符号的char能表示的范围如下图所示:即127~-128
对于无符号数来说,8个二进制为全部用来存储数据,全部为正数,存储的范围是0-255,如下图所示:
short类型无非就是两个字节,具体的范围如下图所示:
有了这些前备知识,再来看这道题目:
char、signed char是有符号的char类型,取值范围是-128-127,可以顺理成章存下-1;具体存放过程如下:
①将整型的-1赋给char类型,10000000000000000000000000000001 ->(转换成补码) 1111111111111111111111111111111111111111;进行截断只要后八位11111111;此时a变量存放的数据就是11111111;
②此时输出按照整型输出,那么11111111需要补足32位,判断是a、b是有符号位的,根据最高位是1则全部补1,这就是整型提升。11111111111111111111111111111111;转换成原码那就是10000000000000000000000000000001;即-1;
但是unsigned char的取值范围是0-255,没有办法存下负数,只能将-1作为正数存下来,-1的二进制表示方法为1
所以,有符号char会打印-1,那么前两个数字会打印-1;而最后一个数字打印255是为什么呢;
分析c:
①将整型的-1赋给char类型10000000000000000000000000000001 ->(转换成补码) 1111111111111111111111111111111111111111;进行截断只要后八位11111111;此时c变量存放的数据就是11111111;
②由于c是无符号char类型,最高位不是符号位,整型提升全部补0,c中最终存储的是00000000000000000000000011111111;即255;而正数三码合一,所以最后输出原码也是255;
答案:a=-1,b= -1,c= 255;
总结:整型提升的时候分为两种情况,对于有符号数来说,根据符号位来补位;对于无符号数来说直接补0;
1.3.2 求输出结果
①这道题目的-128,原码是10000000 00000000 00000000 10000000,补码是
11111111 11111111 11111111 10000000进行截断后取后8位,则为10000000;
②整型提升,因为是有符号数直接按照最高位补1,11111111 11111111 11111111 10000000;
③按照无符号数打印:4294967168;大概42亿左右。
2.浮点型在内存中如何存储
待续......