C语言|数据存放

原码、反码、补码

正数符号位为0,负数符号位为1;
对于正数来说,原码=反码=补码;
对于负数来说,反码=原码除符号位以外其余位全取反,补码=反码+1;
在内存中,只要是整数,都按补码来存放;

对于一个负数-10,其补码是1111 1111 1111 1111 1111 1111 1111 0110(假设int为4bytes),继续对其进行除符号位以外其余位取反,再加1,则可以得到-10的原码。

char

0000 0000 = 0
0000 0001 = 1
0000 0010 = 2

0111 1111 = 127
1000 0000 = -128
1000 0001 = -127

1111 1110 = -2
1111 1111 = -1
signed char:-128~127
unsigned char:0~255

int main()
{
	char a = -1;
	signed char b =-1;
	unsigned char c = -1;

	printf("a=%d,b=%d,c=%d",a,b,c);
	return 0;
}

-1的原码:1000 0000 0000 0000 0000 0000 0000 0001
-1的补码:1111 1111 1111 1111 1111 1111 1111 1111
char是一个字节,发生截断(截取低地址的八个bit,跟数据是小端存储还是大端存储没关系,都是把数据放出来之前进行截断,在存储的时候才会有大小端的问题),因此,a=1111 1111,a用%d打印,发生整型提升(a有符号的,前面全部补1(按符号位来补)),变为1111 1111 1111 1111 1111 1111 1111 1111,而因为内存中存储的是补码,因此前面的1111 1111 1111 1111 1111 1111 1111 1111是补码,求得其原码为1000 0000 0000 0000 0000 0000 0000 0001,因此打印出来是a= -1;
b同上;
c=1111 1111,但因为c是unsigned的,所以c=1111 1111=255,c用%d打印,发生整型提升(c无符号的,前面补0),变为0000 0000 0000 0000 0000 0000 1111 1111,0000 0000 0000 0000 0000 0000 1111 1111为补码,其原码是还是0000 0000 0000 0000 0000 0000 1111 1111(正数原码=反码=补码),因此打印出来是c=255;

int main()
{
	char a[1000];
	int i;
	
	for(i = 0; i < 1000; i++)  // i=0、1、2...1000
	{
		a[i] = -1 - i; // a[i] = -1、-2、... -128、127、...、1、0
	}

	printf("%d", strlen(a)); // 255
}

结果为255;
首先strlen()是通过字符串中’\0’来求字符串的长度;char的取值范围为-128 ~ 127,当a[i]=0时,也就是’\0’,故128+127=255;

大小端

小端字节序存储模式:数据的高位存储在高地址处,低位存储在低地址;
大端字节序存储模式:数据的高位存储在低地址处,低位存储在高地址;
小端与书写顺序相同,大端与书写顺序相反;
注意要看清楚哪边是高地址,哪边是低地址;
在这里插入图片描述
X86是小端,c51、很多arm;

浮点数在内存中的存储

int n = 9;
float* pFloat = (float*)&n;

printf("n的值为:%d\n", n);
printf("* pFloat的值为:%f\n", * pFloat);
* pFloat = 9.0;
printf("n的值为:%d\n", n);
printf("* pFloat的值为:%d\n", * pFloat);

最终的结果为9 0.000000 1091567616 9.000000
说明浮点数在内存中的存储与整数的存储方式不同;
任何一个二进制浮点数都可以表示成: V = ( − 1 ) S ∗ M ∗ 2 E V=(-1)^S*M*2^E V=(1)SM2E
其中S表示符号位,当S=0时,V为正数,当S=1时,V为负数;
M表示有效数字,大于等于1,小于2;
E表示指数;

举例:
V=5.0f == 101.0 == 1.01*2^2 == (-1)^0 * (1.01) * (2^2),因此S=0,M=1.01,E=2;

IEEE 754在这里插入图片描述

在这里插入图片描述

IEEE 754对M和E的规定:

存入内存

  1. 对于M,因为其大于等于1,小于2,因此可以写成1.xxxx(二进制),第一位1可以略去,只保存后面的xxxx;
  2. 对于E,E为无符号整数,如果E为8位,其取值范围为0-255,如果E为11位,其取值范围为0-2047,但E有可能出现负数,因此,需要把实际的E加上127(对于E为8位的情况),加上1023(对于E为11位的情况)得到最终存入E的数据;

从内存中取出

  1. E不全为1或不全为0:E减去127(或1023)得到真实值,再将有效数字M前加第一位的1;
  2. E全为0:E=1-127(或1-1023)得到真实值,有效数字不再加上第一位的1,而是还原为0.xxxx的小数。这样做是为了表示±0,以及接近0的很小的数字;
  3. E全为1:这时,如果有效数字M全为0,表示±无穷大(正负取决于符号位s);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值