由一道笔试题想到的:原码反码和补码
-
- 帖子: 10
- 注册时间: 2010-02-22 12:05
由一道笔试题想到的:原码反码和补码
由一道笔试题想到的:原码反码和补码
这是我从一位CSDN网友的博客上边偶然发现的一道华为笔试题,博主给出了正确答案,但是我对博主的分析有点不太理解。
void main()
{
char *p;
*p=-130;
printf("%d",*p);
}
我们抛开程序的正确性不谈(没有给指针分配空间怎么能对指针进行解引用呢?),仅仅分析一下程序的输出结果。
如果您对原码反码补码的知识非常熟悉或者非常不熟悉,请都跳过下边这段文字直接看对程序的分析,因为我并不想把这篇文章写成对原码反码补码的教学文章。仅仅是想借程序巩固一下这方面的知识。
首先,我们需要分析一下-130在内存中的二进制存储方式。这就引出了有符号整数在内存中的存储方式:有符号整数在内存中是以补码形式存储的。
首先我们给出原码,反码和补码的定义:原码即有符号整数所对应的二进制数,正数的反码和本身一样,负数的反码是对应的原码除符号位以外,其它的数位依次取反,正数的补码和本身一样,负数的补码是对应的反码在末位加1。
计算机中存储方式为补码的原因是为了使减法可以当做加法来算。
其实,如果不采用补码的形式存储,内存中会出现 +0 和 -0,这一现象可以在下边的例子中看到。
举个简单的例子:
如果计算机以8位的方式存储有符号整数,则
原码 反码 补码
1 0000 0001 0000 0001 0000 0001
-1 1000 0001 1111 1110 1111 1111
0 0000 0000 0000 0000 0000 0000
如果是反码存储的话,-1 + 1 = 1111 1111, 1111 1111是 1000 0000 的反码,也就是 -0。
我们接着来分析这个程序:
-130在内存中以补码形式存储,在我的系统中,int类型占4个字节(到今天我也不知道到底是什么东西影响了int的大小,书上说和操作系统的位宽有关,但是我在32位和64位下都试了,结果都是4个字节,或许和编译器有关?如果哪位朋友知道请告知我!谢谢了!)。那么,-130的原码为: 1000 0000 0000 0000 0000 0000 1000 0010,反码为:1111 1111 1111 1111 1111 1111 0111 1101,补码为:1111 1111 1111 1111 1111 1111 0111 1110。
由于*p的数据类型是char,将-130赋值给*p会将数据从低位截断,结果是:0111 1110,那么,输出*p的时候,系统会将数据自动补上0,也就是说,会输出0000 0000 0000 0000 0000 0000 0111 1110。即126。
这是我从一位CSDN网友的博客上边偶然发现的一道华为笔试题,博主给出了正确答案,但是我对博主的分析有点不太理解。
void main()
{
char *p;
*p=-130;
printf("%d",*p);
}
我们抛开程序的正确性不谈(没有给指针分配空间怎么能对指针进行解引用呢?),仅仅分析一下程序的输出结果。
如果您对原码反码补码的知识非常熟悉或者非常不熟悉,请都跳过下边这段文字直接看对程序的分析,因为我并不想把这篇文章写成对原码反码补码的教学文章。仅仅是想借程序巩固一下这方面的知识。
首先,我们需要分析一下-130在内存中的二进制存储方式。这就引出了有符号整数在内存中的存储方式:有符号整数在内存中是以补码形式存储的。
首先我们给出原码,反码和补码的定义:原码即有符号整数所对应的二进制数,正数的反码和本身一样,负数的反码是对应的原码除符号位以外,其它的数位依次取反,正数的补码和本身一样,负数的补码是对应的反码在末位加1。
计算机中存储方式为补码的原因是为了使减法可以当做加法来算。
其实,如果不采用补码的形式存储,内存中会出现 +0 和 -0,这一现象可以在下边的例子中看到。
举个简单的例子:
如果计算机以8位的方式存储有符号整数,则
原码 反码 补码
1 0000 0001 0000 0001 0000 0001
-1 1000 0001 1111 1110 1111 1111
0 0000 0000 0000 0000 0000 0000
如果是反码存储的话,-1 + 1 = 1111 1111, 1111 1111是 1000 0000 的反码,也就是 -0。
我们接着来分析这个程序:
-130在内存中以补码形式存储,在我的系统中,int类型占4个字节(到今天我也不知道到底是什么东西影响了int的大小,书上说和操作系统的位宽有关,但是我在32位和64位下都试了,结果都是4个字节,或许和编译器有关?如果哪位朋友知道请告知我!谢谢了!)。那么,-130的原码为: 1000 0000 0000 0000 0000 0000 1000 0010,反码为:1111 1111 1111 1111 1111 1111 0111 1101,补码为:1111 1111 1111 1111 1111 1111 0111 1110。
由于*p的数据类型是char,将-130赋值给*p会将数据从低位截断,结果是:0111 1110,那么,输出*p的时候,系统会将数据自动补上0,也就是说,会输出0000 0000 0000 0000 0000 0000 0111 1110。即126。
- linjiework
- 帖子: 240
- 注册时间: 2009-07-07 19:52
-
- 帖子: 10
- 注册时间: 2010-02-22 12:05
Re: 由一道笔试题想到的:原码反码和补码
谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?linjiework 写了:学习了~~~
int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。
- linjiework
- 帖子: 240
- 注册时间: 2009-07-07 19:52
Re: 由一道笔试题想到的:原码反码和补码
xiaobo68688 写了:谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?linjiework 写了:学习了~~~
int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。
编译器分普通版本(也就是32位)和64位版本。因为编译器和硬件关系(主要是 CPU)比较密切,所以不同平台下的编译器是不同的。因此在内核里,为了保证在不同平台下,变量的字节数一致,自己定义了一整套数据类型,比如 u32, u8 。
阿呆 : 天下第一呆!
- 友情提醒
- 帖子: 6
- 注册时间: 2010-10-07 20:50
Re: 由一道笔试题想到的:原码反码和补码
从80386开始 cpu地址线就变为32位。int 4字节,就是与32位对齐,这个貌似是ANSI C规定的。编译器不会对标准C基本类型做更改。xiaobo68688 写了:谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?linjiework 写了:学习了~~~
int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。
如果楼主研究过标准C的结构体就会明白。一个结构体的大小是最后一个成员类型决定的。比如
代码: 全选
struct foo1{ char a; int b};
代码: 全选
struct foo {int a; char b};
我想这也是int叫整形原因。。

-
- 帖子: 10
- 注册时间: 2010-02-22 12:05
Re: 由一道笔试题想到的:原码反码和补码
恩,谢谢您,我明白了,但是下边您说的我不太了解,高手呀。友情提醒 写了:从80386开始 cpu地址线就变为32位。int 4字节,就是与32位对齐,这个貌似是ANSI C规定的。编译器不会对标准C基本类型做更改。xiaobo68688 写了:谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?linjiework 写了:学习了~~~
int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。
如果楼主研究过标准C的结构体就会明白。一个结构体的大小是最后一个成员类型决定的。比如代码: 全选
struct foo1{ char a; int b};
是不一样大小的。在foo1里 char a和int之间 编译器会自动补3个字节。如果不这样。cpu取址会出现异常甚至崩溃。代码: 全选
struct foo {int a; char b};
我想这也是int叫整形原因。。
我还得查查资料再回来看看
- eexpress
- 帖子: 58428
- 注册时间: 2005-08-14 21:55
- 来自: 长沙
Re: 由一道笔试题想到的:原码反码和补码
原码反码和补码
就不是C该做的事情哦。C的编译器不同,缺省的字节长都不同的。
出这样题目的,就是脑袋给踢了的人。
那是asm,或者说指令集的事情。
就不是C该做的事情哦。C的编译器不同,缺省的字节长都不同的。
出这样题目的,就是脑袋给踢了的人。
那是asm,或者说指令集的事情。
● 鸣学
- BigSnake.NET
- 帖子: 12522
- 注册时间: 2006-07-02 11:16
- 来自: 廣州
- 联系:
Re: 由一道笔试题想到的:原码反码和补码
一样大小的友情提醒 写了:从80386开始 cpu地址线就变为32位。int 4字节,就是与32位对齐,这个貌似是ANSI C规定的。编译器不会对标准C基本类型做更改。xiaobo68688 写了:谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?linjiework 写了:学习了~~~
int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。
如果楼主研究过标准C的结构体就会明白。一个结构体的大小是最后一个成员类型决定的。比如代码: 全选
struct foo1{ char a; int b};
是不一样大小的。在foo1里 char a和int之间 编译器会自动补3个字节。如果不这样。cpu取址会出现异常甚至崩溃。代码: 全选
struct foo {int a; char b};
我想这也是int叫整形原因。。
^_^ ~~~
要理解递归,首先要理解递归。
地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
要理解递归,首先要理解递归。
地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
- BigSnake.NET
- 帖子: 12522
- 注册时间: 2006-07-02 11:16
- 来自: 廣州
- 联系:
Re: 由一道笔试题想到的:原码反码和补码
而且楼主的解释各种问题 。。
1. p 木有初始化,所以第二行就已经是未定义行为了 。。
2. 即使刚好木有段错误,如果 p 没有对齐,在某些机器上也会崩掉。
3. 溢出是在赋值那里发生的, -130 超出了 char 的范围
1. p 木有初始化,所以第二行就已经是未定义行为了 。。
2. 即使刚好木有段错误,如果 p 没有对齐,在某些机器上也会崩掉。
3. 溢出是在赋值那里发生的, -130 超出了 char 的范围
^_^ ~~~
要理解递归,首先要理解递归。
地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
要理解递归,首先要理解递归。
地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
-
- 帖子: 2841
- 注册时间: 2006-09-11 22:47
Re: 由一道笔试题想到的:原码反码和补码
xiaobo68688 写了:谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?linjiework 写了:学习了~~~
int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。
编译器在不同的平台上是根据对应 CPU 技术参数的推荐来决定的。因为 int 应当是“这个CPU最方便处理的,处理效率最高的整数类型”。这个类型不一定跟CPU位宽相同。
x86_64 位 CPU,在诞生的时候,其指令集就推荐使用 32 位整数,因此 int 是 32 位。——所以说实际上 int 字长与 CPU 位宽没有直接关系。(x86_64 指令集诞生于 K8 时代,各位可以查询 K8 相关文档,其中明确描述了整数 int 应当是 32 位。)
但是,我知道的,有个 HP 的小型机专用64 位CPU,其指令集推荐使用 64 位整数,因此那个平台上的编译器就选择了 64 位。
- 友情提醒
- 帖子: 6
- 注册时间: 2010-10-07 20:50
Re: 由一道笔试题想到的:原码反码和补码
BigSnake.NET 写了:一样大小的友情提醒 写了:从80386开始 cpu地址线就变为32位。int 4字节,就是与32位对齐,这个貌似是ANSI C规定的。编译器不会对标准C基本类型做更改。xiaobo68688 写了:谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?linjiework 写了:学习了~~~
int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。
如果楼主研究过标准C的结构体就会明白。一个结构体的大小是最后一个成员类型决定的。比如代码: 全选
struct foo1{ char a; int b};
是不一样大小的。在foo1里 char a和int之间 编译器会自动补3个字节。如果不这样。cpu取址会出现异常甚至崩溃。代码: 全选
struct foo {int a; char b};
我想这也是int叫整形原因。。


代码: 全选
struct foo1 {char a; int b; char c};
代码: 全选
struct foo2 {int a; char b; char c};
- 会fly的青蛙
- 帖子: 66
- 注册时间: 2010-10-13 13:15
-
- 帖子: 177
- 注册时间: 2010-06-16 20:55
Re: 由一道笔试题想到的:原码反码和补码
不敢苟同.eexpress 写了:原码反码和补码
就不是C该做的事情哦。C的编译器不同,缺省的字节长都不同的。
出这样题目的,就是脑袋给踢了的人。
那是asm,或者说指令集的事情。
比如x&-x这种代码,如果计算机用的不是补码就悲剧了.
-
- 帖子: 1
- 注册时间: 2010-12-08 23:04
Re: 由一道笔试题想到的:原码反码和补码
请问楼主为什么说-130是一个int类型的?
- icmmed
- 帖子: 46
- 注册时间: 2010-12-03 11:08