当前时区为 UTC + 8 小时



发表新帖 回复这个主题  [ 17 篇帖子 ]  前往页数 1, 2  下一页
作者 内容
1 楼 
 文章标题 : 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-22 14:12 

注册: 2010-02-22 12:05
帖子: 10
送出感谢: 0 次
接收感谢: 0 次
由一道笔试题想到的:原码反码和补码
这是我从一位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。


页首
 用户资料  
 
2 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-22 14:22 
头像

注册: 2009-07-07 19:52
帖子: 240
送出感谢: 0 次
接收感谢: 0 次
学习了~~~


int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。


_________________
阿呆 : 天下第一呆!


页首
 用户资料  
 
3 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-22 15:25 

注册: 2010-02-22 12:05
帖子: 10
送出感谢: 0 次
接收感谢: 0 次
linjiework 写道:
学习了~~~


int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。

谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?


页首
 用户资料  
 
4 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-22 21:13 
头像

注册: 2009-07-07 19:52
帖子: 240
送出感谢: 0 次
接收感谢: 0 次
xiaobo68688 写道:
linjiework 写道:
学习了~~~


int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。

谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?



编译器分普通版本(也就是32位)和64位版本。因为编译器和硬件关系(主要是 CPU)比较密切,所以不同平台下的编译器是不同的。因此在内核里,为了保证在不同平台下,变量的字节数一致,自己定义了一整套数据类型,比如 u32, u8 。


_________________
阿呆 : 天下第一呆!


页首
 用户资料  
 
5 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-24 20:38 
头像

注册: 2010-10-07 20:50
帖子: 6
送出感谢: 0 次
接收感谢: 0 次
xiaobo68688 写道:
linjiework 写道:
学习了~~~


int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。

谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?


从80386开始 cpu地址线就变为32位。int 4字节,就是与32位对齐,这个貌似是ANSI C规定的。编译器不会对标准C基本类型做更改。
如果楼主研究过标准C的结构体就会明白。一个结构体的大小是最后一个成员类型决定的。比如
代码:
struct foo1{ char a; int b};
代码:
struct foo {int a; char b};

是不一样大小的。在foo1里 char a和int之间 编译器会自动补3个字节。如果不这样。cpu取址会出现异常甚至崩溃。
我想这也是int叫整形原因。。 :em06


页首
 用户资料  
 
6 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-26 12:51 

注册: 2010-02-22 12:05
帖子: 10
送出感谢: 0 次
接收感谢: 0 次
友情提醒 写道:
xiaobo68688 写道:
linjiework 写道:
学习了~~~


int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。

谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?


从80386开始 cpu地址线就变为32位。int 4字节,就是与32位对齐,这个貌似是ANSI C规定的。编译器不会对标准C基本类型做更改。
如果楼主研究过标准C的结构体就会明白。一个结构体的大小是最后一个成员类型决定的。比如
代码:
struct foo1{ char a; int b};
代码:
struct foo {int a; char b};

是不一样大小的。在foo1里 char a和int之间 编译器会自动补3个字节。如果不这样。cpu取址会出现异常甚至崩溃。
我想这也是int叫整形原因。。 :em06

恩,谢谢您,我明白了,但是下边您说的我不太了解,高手呀。
我还得查查资料再回来看看


页首
 用户资料  
 
7 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-26 13:24 
头像

注册: 2005-08-14 21:55
帖子: 58428
地址: 长沙
送出感谢: 4
接收感谢: 274
原码反码和补码
就不是C该做的事情哦。C的编译器不同,缺省的字节长都不同的。
出这样题目的,就是脑袋给踢了的人。
那是asm,或者说指令集的事情。


_________________
● 鸣学


页首
 用户资料  
 
8 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-26 13:44 
头像

注册: 2006-07-02 11:16
帖子: 12522
地址: 廣州
送出感谢: 0 次
接收感谢: 8
友情提醒 写道:
xiaobo68688 写道:
linjiework 写道:
学习了~~~


int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。

谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?


从80386开始 cpu地址线就变为32位。int 4字节,就是与32位对齐,这个貌似是ANSI C规定的。编译器不会对标准C基本类型做更改。
如果楼主研究过标准C的结构体就会明白。一个结构体的大小是最后一个成员类型决定的。比如
代码:
struct foo1{ char a; int b};
代码:
struct foo {int a; char b};

是不一样大小的。在foo1里 char a和int之间 编译器会自动补3个字节。如果不这样。cpu取址会出现异常甚至崩溃。
我想这也是int叫整形原因。。 :em06


一样大小的


_________________
^_^ ~~~
要理解递归,首先要理解递归。

地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。


页首
 用户资料  
 
9 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-26 13:57 
头像

注册: 2006-07-02 11:16
帖子: 12522
地址: 廣州
送出感谢: 0 次
接收感谢: 8
而且楼主的解释各种问题 。。
1. p 木有初始化,所以第二行就已经是未定义行为了 。。
2. 即使刚好木有段错误,如果 p 没有对齐,在某些机器上也会崩掉。
3. 溢出是在赋值那里发生的, -130 超出了 char 的范围


_________________
^_^ ~~~
要理解递归,首先要理解递归。

地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。


页首
 用户资料  
 
10 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-26 15:11 

注册: 2006-09-11 22:47
帖子: 2841
送出感谢: 0 次
接收感谢: 4
xiaobo68688 写道:
linjiework 写道:
学习了~~~
int 的字节数确实和编译器有关,和运行平台关系不大。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 位。


页首
 用户资料  
 
11 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-11-26 23:45 
头像

注册: 2010-10-07 20:50
帖子: 6
送出感谢: 0 次
接收感谢: 0 次
BigSnake.NET 写道:
友情提醒 写道:
xiaobo68688 写道:
linjiework 写道:
学习了~~~


int 的字节数确实和编译器有关,和运行平台关系不大。int 的字节数在编译的时候就已经确定了。

谢谢您!那么,编译器是根据什么来确定的int的字节数呢?自己喜欢怎么样就怎么样吗?


从80386开始 cpu地址线就变为32位。int 4字节,就是与32位对齐,这个貌似是ANSI C规定的。编译器不会对标准C基本类型做更改。
如果楼主研究过标准C的结构体就会明白。一个结构体的大小是最后一个成员类型决定的。比如
代码:
struct foo1{ char a; int b};
代码:
struct foo {int a; char b};

是不一样大小的。在foo1里 char a和int之间 编译器会自动补3个字节。如果不这样。cpu取址会出现异常甚至崩溃。
我想这也是int叫整形原因。。 :em06


一样大小的


:em06 :em06 sorry...很久没写生疏了。这个例子举的太烂了。。
代码:
struct foo1 {char a; int b; char c};

代码:
struct foo2 {int a; char b; char c};

这样就会不一样。。o(∩∩)o...哈哈 我的失误。对不起楼主。


页首
 用户资料  
 
12 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-12-07 19:43 
头像

注册: 2010-10-13 13:15
帖子: 66
送出感谢: 0 次
接收感谢: 0 次
咦,书上说结构体的大小是其所有元素总和呀,楼上的这两个不还是一样的吗?


_________________
没得玩了


页首
 用户资料  
 
13 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-12-08 15:57 

注册: 2010-06-16 20:55
帖子: 177
送出感谢: 0 次
接收感谢: 1
eexpress 写道:
原码反码和补码
就不是C该做的事情哦。C的编译器不同,缺省的字节长都不同的。
出这样题目的,就是脑袋给踢了的人。
那是asm,或者说指令集的事情。

不敢苟同.
比如x&-x这种代码,如果计算机用的不是补码就悲剧了.


页首
 用户资料  
 
14 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-12-08 23:08 

注册: 2010-12-08 23:04
帖子: 1
送出感谢: 0 次
接收感谢: 0 次
请问楼主为什么说-130是一个int类型的?


页首
 用户资料  
 
15 楼 
 文章标题 : Re: 由一道笔试题想到的:原码反码和补码
帖子发表于 : 2010-12-16 11:45 
头像

注册: 2010-12-03 11:08
帖子: 46
送出感谢: 0 次
接收感谢: 0 次
:em11 学习


_________________
我喜欢忙一点...
Lost Temple...


页首
 用户资料  
 
显示帖子 :  排序  
发表新帖 回复这个主题  [ 17 篇帖子 ]  前往页数 1, 2  下一页

当前时区为 UTC + 8 小时


在线用户

正在浏览此版面的用户:没有注册用户 和 2 位游客


不能 在这个版面发表主题
不能 在这个版面回复主题
不能 在这个版面编辑帖子
不能 在这个版面删除帖子
不能 在这个版面提交附件

前往 :  
本站点为公益性站点,用于推广开源自由软件,由 DiaHosting VPSBudgetVM VPS 提供服务。
我们认为:软件应可免费取得,软件工具在各种语言环境下皆可使用,且不会有任何功能上的差异;
人们应有定制和修改软件的自由,且方式不受限制,只要他们自认为合适。

Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
简体中文语系由 王笑宇 翻译