无符号和有符号
在C语言里,整数的表示有有符号和无符号两种
无符号 | 有符号 | 32位 | 64位 |
---|---|---|---|
unsigned char | char | 1 | 1 |
unsigned short | short | 2 | 2 |
unsigned int | int | 4 | 4 |
unsigned long | long | 4 | 8 |
unsigned long long | long long | 8 | 8 |
无符号是用原码表示,有符号使用补码表示,那么他们的加,减,乘,积,取反是否有区别呢?
加
测试代码
#include <stdio.h>
int main()
{
int a = 10 , b= 10;
unsigned c = 10, d= 10;
a = a+b;
c = c+d;
}
无符号加法和有符号加法都是使用使用 add指令,我感觉应该很清晰
减
#include <stdio.h>
int main()
{
int a = 10 , b= 10;
unsigned c = 10, d= 10;
a = a-b;
c = c-d;
}
无符号加法和有符号减法都是使用使用 sub指令,我感觉也应该很清晰,毕竟补码的作用就是把原来减法运算统一成加法运算,所以本质上sub指令和add指令是一样的
乘
测试代码:
#include <stdio.h>
int main()
{
int a = 10,b = 10;
unsigned c = 10,d = 10;
a *=b;
c*=d;
}
通过反汇编之后,发现无论是有符号int,还是无符号unsigned int,使用的都是无符号乘法指令imul。
所以无符号乘法和有符号乘法都是一样的(后面证明)
那为什么指令集系统里要用imul(无符号乘法)和mul(有符号乘法)呢?
经过Google发现:imul和mul的确是一样的,唯一的区别是执行完后对标志位flags中CF和OF设置。但是标志位是我们不care的。
实在想知道的:可以看下边ORACLE 提供的IA-32 汇编语言参考手册中imul和mul对标志位flags的影响
ORACLE imul指令
ORACLE mul指令
取反
#include <stdio.h>
int main()
{
int a = 10;
unsigned c = 10;
a = -a;
c = -c;
}
可能会有质疑:无符号求反,好像是UB,的确,无符号求反在GCC上可以通过编译,但是在visual studio上报错。但是本文是对于csapp里的总结,所以就当学知识了。
ref
CSAPP
ORACLE imul
ORACLE mul
x86汇编当中imull 和 mull 区别