编程语言
首页 > 编程语言> > 【汇编语言与计算机系统结构笔记02】整数的计算机表示与运算,C中的无符号字符(unsigned)和带符号字符(signed),补码,一些例题

【汇编语言与计算机系统结构笔记02】整数的计算机表示与运算,C中的无符号字符(unsigned)和带符号字符(signed),补码,一些例题

作者:互联网

本次笔记内容:
03.整数的计算机表示与运算

文章目录

预备知识

注意在存储领域,不是以1024进位的,是以1000进位的。

在x86中,默认一个Word为16个比特:

数制

数的机器表示

机器字(machine word)长:

机器字在内存中的组织

地址按照字节(byte)来定位:

在这里插入图片描述

字节序(Byte Ordering)

一个机器字内的各个字节如何排序?

Big Endian:Sun,PowerPC,Internet

Little Endian:x86

例子如下。

0x100 0x101 0x102 0x103
01 23 45 67
67 45 23 01

如上,要存储数值为0x01234567的数,上面是LSB,下面是x86的存储方式。

socket就有将本地字节序与网络字节序的功能。

再举一个例子:

Decimal: 15213
Binary: 0011 1011 0110 1101
Hex: 3 B 6 D

对于以下三种实现:

int A = 15321;
int B = -15213;
long int C = 15213;

在IA32, x86-64, Sun设备上的存储分别为:

在这里插入图片描述

整数表示

C语言中基本数据类型的大小(in Bytes):

C Data Type Typical 32-bit x86-32 x86-64
char 1 1 1
short 2 2 2
int 4 4 4
long 4 4 8
long long 8 8 8
float 4 4 4
double 8 8 8
long double 8 10/12 10/16
char * or any other pointer 4 4 8

计算机中整数的二进制编码方式

w表示字长,对于无符号数: B 2 U ( X ) = ∑ i = 0 w − 1 x i ⋅ 2 i B2U(X) = \sum^{w-1}_{i=0} x_i \cdot 2^i B2U(X)=i=0∑w−1​xi​⋅2i

对于带符号数(补码,Two’s Complement): B 2 T = − x w − 1 ⋅ 2 w − 1 + ∑ i = 0 w − 2 x i ⋅ 2 i B2T = -x_{w-1} \cdot 2^{w-1} + \sum^{w-2}_{i=0} x_i \cdot 2^i B2T=−xw−1​⋅2w−1+i=0∑w−2​xi​⋅2i

对于下列实现:

short int x = 15213;
short int y = -15213;

其存储为:

Decimal Hex Binary
x 15213 3B 6D 00111011 01101101
y -15213 C4 93 11000100 10010011

对于负数(补码),即取反再加一。

符号位(sign bit):

无符号数与带符号数

范围

在带符号数中,负数范围个数总比整数范围个数多1,举例:

转换

无符号数与带符号数之间的转换:

在这里插入图片描述

上图为无符号数和带符号数的关系。

C语言中的无符号数和带符号数

常数(Constants):

如果无符号数与带符号数混合使用,则带符号数默认转换为无符号数,包括比操作符。

下面是例题,比较常数1和常数2的关系:

Constant_1 Constant_2 Relation Evaluation
0 0U == unsigned
-1 0 < signed
-1 0U > unsigned
2147483647 -2147483647-1 > signed
2147483647U -2147483647-1 < unsigned
-1 -2 > signed
(unsigned) -1 -2 > unsigned
2147483647 2147483648U < unsigned
2147483647 (int) 2147483648 > signed

将负的带符号数转换为无符号数时,总比正的带符号数大,可以参考上面的映射示意图。

何时采用无符号数

建议:不能仅仅因为取值范围是非负而使用。只在两种情况使用:

不能乱用unsigned的例子:

// example I
unsigned i;
for (i = cnt - 2; i >= 0; i--)
	a[i] += a[i+1];
// 永远无法结束,i恒大于等于0
// example II
#define DELTA sizeof(int)
int i;
for (i = CNT; i-DELTA >= 0; i-= DELTA)
	...
// sizeof()返回unsigned,而i-=DELTA运算后,i被转换为unsigned,导致for无法退出
加法

无符号数和带符号数(补码)加法所用的x86机器指令都是同一条类型。加法就是两个位串加起来。

无符号整数除以2的k次幂

在编译时,如果遇到无符号整数除以2的k次幂,不调用除法指令(硬件的除法非常慢),而调用逻辑右移。

u >> k gives ⌊ u / 2 k ⌋ \lfloor u / 2^k \rfloor ⌊u/2k⌋

// C Function
unsigned udiv8(unsigned x)
{
	return x / 8;
}
// Compiled Arithmetic Operations
shrl	$3, %eax
// Explanation
# Logical shift
return x >> 3;
带符号整数除以2的k次幂

u >> k gives ⌊ u / 2 k ⌋ \lfloor u / 2^k \rfloor ⌊u/2k⌋

但是如果 x < 0 x < 0 x<0,出现舍入错误。

解决方案:

// C Function
int idiv8(int x)
{
	return x / 8;
}
// Compiled Arithmetic Operations
	testl	%eax, %eax
	js		L4
L3:
	sarl	$3, %eax
	ret
L4:
	addl	$7, %eax
	jmp		L3
// Explanation
# Logical shift
if x < 0
	x += 7;
# Arithmetic shift
return x>>3;

Integer C Puzzles

int x = foo();
int y = bar();
unsigned ux = x;
unsigned uy = y;

x<0 infer ((x*2)<0)

不对,可能溢出。

ux>=0

对。

x & 7 == 7 infer (x<<30)<0

对。

7即111,x & 7 == 111,即x低位的3位为111。

x是int类型(32位),111向左移30位,则符号位为1,是负数。

ux > -1

不对,ux一定是小于等于-1的(-1转换为unsigned后,大)。

x > y infer -x < -y

不对,因为不一定。负数的表示范围比正数大1,若y为-128,推论将不成立。

x * x >= 0

不对,可能溢出,高位被截断。

x > 0 && y > 0 infer x + y > 0

不对,可能溢出。

x >= 0 infer -x <= 0

对。

x <= 0 infer -x >= 0

不对,-128为反例。

(x|-x)>>31 == -1

不对,0位反例。

ux>>3 == ux/8

对。

x >> 3 == x/8

不对,负数为反例。

x & (x-1) != 0

不对,x取0为反例。

另一道练习题

已知某32位整数X,其值为-101,则其16进制补码为(0xFFFFFF9B),另一32位整数Y的补码为0xFFFFFF6A,则X+Y的16进制补码(32位)为(0xFFFFFF05),X-Y的16进制补码为(0x31)。

解:

标签:字符,ux,符号,带符号,unsigned,整数,int,例题
来源: https://blog.51cto.com/u_15279775/2937839