C语言中数据在内存中的存储

1.整形

1.1整形的三种编码方式,原码,反码,补码 plus无符号整形的编码

在c语言中,原码即为该数字的二进制形式,且最高位为符号位。负数的反码是原码的按位取反的结果。负数的补码则是反码+1的结果。正整形的原反补都是相同的

无符号整形在内存中无符号位这一说法,就像是数学中的绝对值,最高位不再决定符号,而是参加值大小的决定。

举例:

int a = 1;//int 类型在内存中占据四个字节,共有4*8个二进制位,且最高位为符号位
//a的原码:00000000 00000000 00000000 00000001
//a的反码:00000000 00000000 00000000 00000001
//a的补码:00000000 00000000 00000000 00000001
//可知正数的原码反码补码是相同的
//(注意,最高位为符号位,符号位为1时数字为负数,为0时为正数)
int b = -1;
//b的原码:10000000 00000000 00000000 00000001 
//b的反码:11111111 11111111 11111111 11111110 (除去符号位外按位取反即为负数的反码)
//b的补码:11111111 11111111 11111111 11111111 (在反码基础上+1) 
unsigned int c = 1;
//其在计算机中的存储方式与正整形相同:
//00000000 00000000 00000000 00000001

1.2补码的意义以及如何转换为十进制

在计算机中整形数值的运算和存储都是通过补码(无符号整型和正整形补码和原码相同)进行的,通过补码运算我们可以将加法和减法合并为加法。

举例

int a = 1;//补码为 00000000 00000000 00000000 00000001
int b = -1;//补码为11111111 11111111 11111111 11111111 
int c = a + b;//a + b 等同于 1 - 1 上面二值相加结果为 00000000 00000000 00000000 00000000 
printf("%d",c);//打印出0

补码转化十进制公式:

若为n位二进制数为abcdfghijkl.........z(各位取值只有01)其十进制表现形式为:

-a*(2^{n-1})+b*(2^{n-2})+c*(2^{n-3})+..........+z*2^{0}

得到的轮回结论

由此公式我们可知,在计算机的存储中若一味地给变量增加数值,在成为正极限数值(受限于数据类型的字节大小)后又会变成负极限值,即只有a为1,其余都为0的情况,最后又随着给变量增加数值,数值又会慢慢回到-1,即全1的情况,再加1又会变成零,继续给变量增加数值又会变成最大正极限数值,即一次轮回。如图所示:

 

2.浮点型

2.1浮点型如何转化为二进制

浮点型数据转化为二进制,其整数部分与前面的整形转化是相同的,不同之处在于小数点后面的那个部分,其实也很简单:将小数部分*2,第一次乘若得到1则在第一位位写上1,并去掉一继续下一次乘2,若得到0则在第一位写上0,并且继续下一次乘法。重复以上操作直到小数部分全为零为止。(注:有时会有小数部分乘不尽的情况,根据情况进行舍去相应位数即可)

2.2浮点型在二进制中如何存储

C语言的浮点数是遵循IEEE(Institute of Electrical and Electronics Engineers)电气电子工程师学会的754标准。其标准是将二进制转化为如下形式:

(-1)^{S}*M*2^{E}第一部分s为最高位,即符号位,第二部分M为有效数字部分即1.1101101(举例),第三部分即为阶码部分。

而在电脑中,计算机存储的方式由高到底分别为SEM,如图:

其中S决定符号,只占一位,E指数部分则需要加上偏移量(float为127 double为1023) ,在float中占八个bit double中占11个bit。M则为有效数字部分去掉整数的部分,按照上面给出的有效数字举例,其储存则为“1101101后面加上若干个零”。在float中M占23个bit,在double中M占52个bit。

下面给出float类型11.101如何存储的示例

 3.大小端存储

1.概念

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,数据从高位往低位放;这和我们的阅读习惯一致。

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

来源:百度百科.大小端模式

来自本人的记忆的小技巧:在现实世界中,高位是一直延伸向无穷的,所以我们可以认为高位并不是一个数的端点,而低位一直是在小数点之前或者根本没有小数点,也就是永远的第零位。那么我们就可以认为第零位即低位为这一串数字的“端”。而大端就是把低字节放在较高地址位上,地址数值大,放着所谓的“端”  即为大端,小端也就同样能得出了。

2.判断大小端的代码

主要思路是利用char* 访问一个字节内容

void judge_system()
{
	int a = 1;
	char* lookin = (char *) & a;
	if (*lookin)
	{
		printf("小端");
	}
	else
	{
		printf("大端");
	}
}

最后再看一个“奇怪”的代码

void strange(void)
{
    int i = 0;
    int a[10] = {0};
    for(i = 0; i<50; i++)
    {
        printf("hello");
        a[i] = 0;
    }
}

这个代码再vs2022 x86 debug的版本下运行会陷入死循环。可是这是为什么呢,明明只是让他进行五十次循环呀?

如果陷入死循环,那必然有他的道理。

在堆栈的过程中,c语言通常是从高往低去申请地址来用的,就会形成如下图的情况

随着i的增加,慢慢地又会越界访问到上面的地址,上面的i又会被改成0,最后导致了死循环。

但是在release版本下就不会出现这种情况,说明在release版本下编译器也会对代码的解读作出相应优化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值