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 也一样.