计算机中,-1到底是什么? 它是怎样表示的。

------------------------------------------------------------
author: hjjdebug
date:   Tue Jun 10 10:27:23 CST 2014
------------------------------------------------------------
计算机中,-1到底是什么? 他是怎样表示的。
答: -1 是个最大的负整数,0-1=-1, -1在计算机中用补码表示。
-1的表现形式与内存类型相关,通常,-1用32bits 补码表示(0xffffffff),根据上下文,
也可能被变为8bits(0xff), 16bits(0xffff), 64bits
 

看代码:

 

#include <stdio.h>

int main(int argc, char *argv[])
{
    int a = -1;     // 默认的, -1 为4byes 0xffffffff
    long int b = -1; // 根据上下文, 内存类型为8bytes, -1 被转换为 0xffffffffffffffff
    char c = -1;    // 根据上下文, 内存类型为1bytes, -1 被转换为 0xff
    short d = -1;   // 根据上下文, 内存类型为2bytes, -1 被转换为 0xffff
    printf("%d %x\n",-1,-1);    // nature
    printf("%ld %lx\n",(long int)-1,(long int)-1); // -1 被强制转换为64bits(-1)
    // char 数据类型用32bits 表示,不会触发数据变换, 上下文要求传递函数参数,故仍用32bits 表示。
    printf("%c %x\n",(char)-1,(char)-1);  
    printf("size of int: %d\n",sizeof(int));
    printf("size of long int: %d\n",sizeof(long int));
    return 0;
}


看 gdb 反汇编代码, 加深理解!

 

 

(gdb) disassemble /m main
Dump of assembler code for function main:
4	{
   0x00000000004004c4 <+0>:	push   %rbp
   0x00000000004004c5 <+1>:	mov    %rsp,%rbp
   0x00000000004004c8 <+4>:	sub    $0x30,%rsp
   0x00000000004004cc <+8>:	mov    %edi,-0x24(%rbp)
   0x00000000004004cf <+11>:	mov    %rsi,-0x30(%rbp)

5		int a = -1;		// 默认的,-1 为4byes 0xffffffff 
=> 0x00000000004004d3 <+15>:	movl   $0xffffffff,-0x14(%rbp)

6		long int b = -1; // 根据上下文, 内存类型为8bytes, -1 被转换为 0xffffffffffffffff
   0x00000000004004da <+22>:	movq   $0xffffffffffffffff,-0x10(%rbp)

7		char c = -1;	// 根据上下文, 内存类型为4bytes, -1 被转换为 0xff
   0x00000000004004e2 <+30>:	movb   $0xff,-0x3(%rbp)

8		short d = -1;	// 根据上下文, 内存类型为1bytes, -1 被转换为 0xffff
   0x00000000004004e6 <+34>:	movw   $0xffff,-0x2(%rbp)

9		printf("%d %x\n",-1,-1);	// nature
   0x00000000004004ec <+40>:	mov    $0x400678,%eax
   0x00000000004004f1 <+45>:	mov    $0xffffffff,%edx
   0x00000000004004f6 <+50>:	mov    $0xffffffff,%esi
---Type <return> to continue, or q <return> to quit---
   0x00000000004004fb <+55>:	mov    %rax,%rdi
   0x00000000004004fe <+58>:	mov    $0x0,%eax
   0x0000000000400503 <+63>:	callq  0x4003b8 <printf@plt>

10		printf("%ld %lx\n",(long int)-1,(long int)-1); // -1 被强制转换为64bits(-1)
   0x0000000000400508 <+68>:	mov    $0x40067f,%eax
   0x000000000040050d <+73>:	mov    $0xffffffffffffffff,%rdx
   0x0000000000400514 <+80>:	mov    $0xffffffffffffffff,%rsi
   0x000000000040051b <+87>:	mov    %rax,%rdi
   0x000000000040051e <+90>:	mov    $0x0,%eax
   0x0000000000400523 <+95>:	callq  0x4003b8 <printf@plt>

11		// char 数据类型用32bits 表示,不会触发数据变换, 上下文要求传递函数参数,故仍用32bits 表示。
12		printf("%c %x\n",(char)-1,(char)-1);  
   0x0000000000400528 <+100>:	mov    $0x400688,%eax
   0x000000000040052d <+105>:	mov    $0xffffffff,%edx
   0x0000000000400532 <+110>:	mov    $0xffffffff,%esi
   0x0000000000400537 <+115>:	mov    %rax,%rdi
   0x000000000040053a <+118>:	mov    $0x0,%eax
   0x000000000040053f <+123>:	callq  0x4003b8 <printf@plt>

13		printf("size of int: %d\n",sizeof(int));
   0x0000000000400544 <+128>:	mov    $0x40068f,%eax
   0x0000000000400549 <+133>:	mov    $0x4,%esi
   0x000000000040054e <+138>:	mov    %rax,%rdi
   0x0000000000400551 <+141>:	mov    $0x0,%eax
   0x0000000000400556 <+146>:	callq  0x4003b8 <printf@plt>

14		printf("size of long int: %d\n",sizeof(long int));
   0x000000000040055b <+151>:	mov    $0x4006a0,%eax
   0x0000000000400560 <+156>:	mov    $0x8,%esi
   0x0000000000400565 <+161>:	mov    %rax,%rdi
   0x0000000000400568 <+164>:	mov    $0x0,%eax
   0x000000000040056d <+169>:	callq  0x4003b8 <printf@plt>

15		return 0;
   0x0000000000400572 <+174>:	mov    $0x0,%eax

16	}
   0x0000000000400577 <+179>:	leaveq 
   0x0000000000400578 <+180>:	retq   

End of assembler dump.
(gdb) 

 

通俗的解释一下: 谈负数必然要谈到模的概念,  例如8bit的二进制它的模就是256,  钟表它的模就是12, 模就是所有成员的总个数,超过这个数就要取余数降下来.

0xff 我们说它是256, 也可是说它是-1(相对于8bit的模),因为它到模256的距离只差1.

你也可以这么解释, 你看最高位bit7是1,所以是负数, 后面的bit6-bit0是一个补碼表示的数. 那它表示负几呢? 把bit6-bit0取反再加1, 就是1了, 所以是-1, 啊, 好绕啊! 解释都是自圆其说就可以了.

理论就是自圆其说且经得起推理的.

所以重申一下这个事实. 对于客观实在0xff , 你可以说它是255, 也可以说它是-1, 因为你的解释体系不同.

补碼是什么? 补碼就是到模的距离.

二进制的补碼为什么是原碼取反再加1?  因为所有的原碼加上它的反碼就变成全1了,是最大的二进制数, 在加1, 就到了模了.

因为原碼加补碼等于模,现在推出原碼加反碼再加1也等于模,所以补碼就等于反碼加1.

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值