免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6321 | 回复: 7
打印 上一主题 下一主题

这道题是什么意思!!! [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-05-07 21:50 |只看该作者 |倒序浏览
一道面试题


unsigned long val;
char a=0x96;
char b=0x81;

val= b<<8 | a;

问val=___?

论坛徽章:
1
荣誉版主
日期:2011-11-23 16:44:17
2 [报告]
发表于 2006-05-07 22:18 |只看该作者
相当于把a赋给val。
但是val是无符号的long型,
而a却是char型,需要向上提升到unsigned long型。
于是在a(10010110)的八位二进制数字前面加了24个1,
11111111111111111111111110010110
算一算应该是多少吧,4294967190。

论坛徽章:
0
3 [报告]
发表于 2006-05-08 11:08 |只看该作者
我算了一下  答案应该是对的``

论坛徽章:
0
4 [报告]
发表于 2006-05-08 12:12 |只看该作者
请教一下,为什么前面是填充1,哪里有这方面问题的比较详细的说明。
谢谢。

论坛徽章:
0
5 [报告]
发表于 2006-05-08 12:44 |只看该作者
val明明是unsigned,怎么提升是在前面加1呢?不解

论坛徽章:
0
6 [报告]
发表于 2006-05-08 13:24 |只看该作者
原帖由 lenovo 于 2006-5-7 22:18 发表
相当于把a赋给val。
但是val是无符号的long型,
而a却是char型,需要向上提升到unsigned long型。
于是在a(10010110)的八位二进制数字前面加了24个1,
11111111111111111111111110010110
算一算应该是多少吧,4294967190。


那么请问:

假设1:
unsigned long val;
char a=0x60;
char b=0x50;

val= b<<8 | a;

问val=___? 0xFFFFFF60 ? 不对吧。

假设2:
unsigned long val;
char a=-0x60;
char b=-0x50;

val= b<<8 | a;

问val=___?

假设3:
unsigned long val;
char a=0x600;
char b=0x500;

val= b<<8 | a;

问val=___?

我的不完全解答:
已知:
        unsigned long val;
        char a = 0x96;
        char b = 0x81;
求:
        val = b << 8 | a;

解答:

不带限定符的char类型对象是否带符号取决于具体机器
(The C Programming Language 2.2节)。

情况1(大多数机器都是这种情况):
假定不带限定符的char类型为带符号数,
即char相当于signed char (取值范围-128 ~ 127)。

8位:
0x96 = 1001 0110 = 150 > 127
0x81 = 1000 0001 = 129 > 127
所以扩展时空位填1。
32位:
0xffffff81 = 1111 1111 1111 1111 1111 1111 1000 0001
<< 8
----------------------------------------------------
0xffff8100 = 1111 1111 1111 1111 1000 0001 0000 0000
0xffffff96 = 1111 1111 1111 1111 1111 1111 1001 0110
|
----------------------------------------------------
0xffffff96 = 1111 1111 1111 1111 1111 1111 1001 0110 = 4294967190

情况2:
假定不带限定符的char类型为带符号数,
即char相当于unsigned char (取值范围0 ~ 255)。

8位:
0x96 = 1001 0110 < 255
0x81 = 1000 0001 < 255
所以扩展时空位填0。
32位:
0x00000096

0x00000081 << 8 = 0x00008100 = 33024
                  0x00000096
                  |
                  ------------------
                  0x00008196 = 33174
      

问题扩展:
情况1中,
1)如果a、b取值范围在-128 ~ 127之内,扩展时空位如何填?
2)如果a、b取值范围在< -128 或 > 127 呢?
3)如果a、b中某个取值范围在-128 ~ 127之内,另一个在< -128 或 > 127 。

情况2中,如果a、b取值范围在
1)0 ~ 255之内,扩展时空位如何填?
2)< 0 或 > 255 呢?
3)如果a、b中某个取值范围在0 ~ 255之内,另一个在< 0 或 > 255 。

论坛徽章:
0
7 [报告]
发表于 2006-05-08 15:33 |只看该作者
好象结果也不一定的,c陷阱与缺陷7.4节有一点介绍。
反汇编的结果:在我的gcc上
unsigned long val;
char a = 0x96;
char b = 0x81;

val = a;
printf("val=%u=0x%x\n", val, val);
反汇编后主要代码是:
movb $0x96, 0xfffffffb(%ebp)
movb $0x81, 0xfffffffa(%ebp)
movsbl 0xfffffffb(%ebp), %eax
mov %eax, 0xfffffffc(%ebp)
好象movsbl指令是关键。这个地址有这个指令的一点点介绍:
http://bigwhite.blogbus.com/logs/2005/11/

论坛徽章:
0
8 [报告]
发表于 2006-05-10 00:44 |只看该作者
如上面 westgarden 所指出的那样,char 到底是 unsigned char 还是 signed char 取决于具体实现。相应地,这个题的结果也是实现相关的。

要了解你使用的系统中 char 到底是有符号的还是无符号的也很简单。比如,执行下面的程序可以告诉你这一点:
  1. /* Program to determine what the char is in your system.
  2. */
  3. #include <stdio.h>
  4. #include <limits.h>

  5. int main( void )
  6. {
  7.   if ( CHAR_MAX == SCHAR_MAX ) {
  8.     printf( "char is signed char.\n" );
  9.   }
  10.   else if ( CHAR_MAX == UCHAR_MAX ) {
  11.     printf( "char is unsigned char.\n" );
  12.   }
  13.   else {
  14.     printf( "It is impossible to reach here.\n" );
  15.   }

  16.   return 0;
  17. }
复制代码


再回到题目上来。根据 char 的不同实现题目可以有两种结果:

1. char 是 signed char 的情况

此时无论是 0x96 还是 0x81 (这两个都是 int 型)都超过了 signed char 的表示范围(-128 ~ +127)。根据标准的规定,变量 a 和 b 的结果是无定义的,从而 val 的结果也是无定义的。

虽然结果是无定义的,不过许多实现都直接截断整数的最低一个字节来作为 char 型变量的值,其结果换算为有符号数的十进制表示分别是 -106 和 -127(如果负数用2的补数表示),其内存存储用十六进制表示仍分别为 0x96 和 0x81。

在进行 val= b<<8 | a 运算的时候首先进行 b<<8 向左移位运算。由于 b 是一个负数,根据标准的规定,对负数进行左移运算是无定义的行为。

综上所述,当 char 是 signed char 时 val 的结果是无定义的。也就是说,即使你得到了一个结果,这个结果也是得不到标准的保证的;因为其它的实现可能是另外一个结果,也可能根本就得不到一个结果。

2. char 是 unsigned char 的情况

由于整数 0x96 和 0x81 都在 unsigned char 的取值范围内(0 ~ 255),所以变量 a 和 b 的值也分别是 0x96 和 0x81。

对于无符号数的移位运算的结果总是有定义的。不过需要注意的是:在进行 << 运算和 | 运算的时候要用到“整数提升(integer promotion)”规则,首先把 char 型变量 a 和 b 转换为 int (注意不是 val 的类型 unsigned long),这样 b<<8 | a 的结果是 int,最后再把这个 int 型的值转换为 unsigned long 给 val 赋值。

如果 sizeof(int) = 4,那么对于 unsigned char 0x96 (其二进制表示是 10010110),提升为 int 时是 0x00000096 (表现在二进制上就是直接在前面补0)。如果0x96 (二进制表示 10010110) 作为 signed char 处理,那么由于最高位是 1,所以是一个负值(-106),把这个 -106 提升为 int 型其值仍然是 -106,作为 int 的 -106 的内部表示是 0xFFFFFF96(表现在二进制上就是在前面补1)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP