深刻理解unsigned char, signed char. 有符号数,无符号数.

author: hjjdebug
date: 2017-08-25

1. unsigned char, 它的模256是如何起作用的.

#include <stdio.h>

int main()
{
	unsigned char a=220;
	unsigned char b=221;
	unsigned char c=a+b;    // a+b 已经超出了unsigned char 范围, c 如何保证的仍然是一个byte.
	printf("data is %d\n",c);
	return 0;
}


x86 反汇编.
	unsigned char a=220;
 8048432:	c6 44 24 1d dc       	movb   $0xdc,0x1d(%esp) // 立即数存入内存(栈) 低
	unsigned char b=221;
 8048437:	c6 44 24 1e dd       	movb   $0xdd,0x1e(%esp) // 立即数存入内存(栈) 高, 可见栈分配是从最后一个函数变量开始先分配的. 
	unsigned char c=a+b;
 804843c:	8a 44 24 1e          	mov    0x1e(%esp),%al
 8048440:	8a 54 24 1d          	mov    0x1d(%esp),%dl
 8048444:	01 d0                	add    %edx,%eax
 8048446:	88 44 24 1f          	mov    %al,0x1f(%esp) // **我们看到只选取了al, 高位已自然丢失.,存入到栈变量(更高地址)**
	printf("data is %d\n",c);
 804844a:	0f b6 44 24 1f       	movzbl 0x1f(%esp),%eax  // 取一个byte, 前面进行了0扩展到4字节%eax寄存器.
 804844f:	89 44 24 04          	mov    %eax,0x4(%esp) // 放到堆栈上,进行参数传递.
 8048453:	8d 83 00 e5 ff ff    	lea    -0x1b00(%ebx),%eax // 取得字符串地址.可认为是立即数,加%ebx 是位置无关代码引入的.
 8048459:	89 04 24             	mov    %eax,(%esp)		//放入字符串地址
 804845c:	e8 8f fe ff ff       	call   80482f0 <printf@plt>
	return 0;

模256,原来超出的高位自然丢失! 因为编译器只使用了低8bits, 用al 参与运算

2. signed char, 最高位代表符号位是如何处理的?

#include <stdio.h>

int main()
{
	char a=120;
	char b=121;
	char c=a+b;
	printf("data is %d\n",c); //a+b 作为有符号数已经溢出, 如何处理的? 如何付给的char c?
	return 0;
}
打印结果: data is -15 


x86 反汇编, 分析同前面类似. 
奇怪吗? 有符号char 与无符号char 运算完全一致, 但是,在数据表现方面就不一样了. 它的最高位符号位进行了扩展
	char a=120;
 8048432:	c6 44 24 1d 78       	movb   $0x78,0x1d(%esp)
	char b=121;
 8048437:	c6 44 24 1e 79       	movb   $0x79,0x1e(%esp)
	char c=a+b;
 804843c:	8a 54 24 1d          	mov    0x1d(%esp),%dl
 8048440:	8a 44 24 1e          	mov    0x1e(%esp),%al
 8048444:	01 d0                	add    %edx,%eax
 8048446:	88 44 24 1f          	mov    %al,0x1f(%esp)
	printf("data is %d\n",c);
 804844a:	0f be 44 24 1f       	movsbl 0x1f(%esp),%eax	//1byte数据进行4byte扩展, 符号位进行了扩展, 可以判定是一个符号char.
 804844f:	89 44 24 04          	mov    %eax,0x4(%esp)
 8048453:	8d 83 00 e5 ff ff    	lea    -0x1b00(%ebx),%eax
 8048459:	89 04 24             	mov    %eax,(%esp)
 804845c:	e8 8f fe ff ff       	call   80482f0 <printf@plt>
	return 0;

此例,在printf时char 进行数据扩展,实际上是符号扩展,而unsigned char 是0扩展,从汇编指令上可以区分.
所以说, 有符号数,无符号数都是那个数, 看打印如何解释它了.

3. 另一个问题: 符号数-1, 与无符号数0xFFFFFFFF又是如何区分的?

答, 他们是不能直接区分的, 它们在bit位表示上是一致的. 如果用%d打印,输出是-1,用%x打印,输出是0xffffffff
区分到底是有符号数还是无符号数,要看他们数据扩展,数据比较等的表现形式.
给出例子:

#include <stdio.h>
int main()
{
	int i=-1;
	unsigned int j=0xffffffff;
	printf("i is %d\n",i);
	printf("j is %d\n",j);
	return 0;
}
结果是什么呢?
i is -1
j is -1
对应的汇编指令.

	int i=-1;
 8048432:	c7 44 24 18 ff ff ff 	movl   $0xffffffff,0x18(%esp)  // 看见了吗? -1 就是这么表示的. 这就是所谓的补码表示!
 8048439:	ff 
	unsigned int j=0xffffffff;
 804843a:	c7 44 24 1c ff ff ff 	movl   $0xffffffff,0x1c(%esp)
 8048441:	ff 
	printf("i is %d\n",i);
 8048442:	8b 44 24 18          	mov    0x18(%esp),%eax
 8048446:	89 44 24 04          	mov    %eax,0x4(%esp)
 804844a:	8d 83 10 e5 ff ff    	lea    -0x1af0(%ebx),%eax
 8048450:	89 04 24             	mov    %eax,(%esp)
 8048453:	e8 98 fe ff ff       	call   80482f0 <printf@plt>
	printf("j is %d\n",j);
 8048458:	8b 44 24 1c          	mov    0x1c(%esp),%eax
 804845c:	89 44 24 04          	mov    %eax,0x4(%esp)
 8048460:	8d 83 19 e5 ff ff    	lea    -0x1ae7(%ebx),%eax
 8048466:	89 04 24             	mov    %eax,(%esp)
 8048469:	e8 82 fe ff ff       	call   80482f0 <printf@plt>

阅读此, 希望你能理解,-1就是最大的无符号数,
最大的符号数是最大的无符号数/2
最大的符号数加1为最小的符号数.
姑且说这是有符号数的性质吧.

有符号数的最高bit代表符号位,0为正数,1为负数,负数用补码表示
这个称之为有符号数的定义吧.

数据就摆在那里,至于你把它当符号数,还是当无符号数,全看你的解释了。

理解了signed,unsigned byte, 则signed, unsigned short 是一个道理,int, unsigned int 也一样.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值