- 论坛徽章:
- 0
|
书本 p24例题 2.10
一、问题提出:
整型变量 j 被赋值为 '\376',那么 j 的值是多少呢? 简化后的代码如下
- #include <stdio.h>
- int main()
- {
- int j;
- j='\376';
- printf("%d\n", j);
- }
复制代码
书本说,输出的值应该为 -2,用 gcc 编译后运行,得到相同的结果。
二、ASCII 码表
j 变 -2,是因为编译系统把 '\376' 理解成负数了。我们知道,一个字符在 C 语言中被表示成其相应的整数编码。通常情况下,这个编码就是 ASCII 码。'\376' 对应的字符为........查一下 ASCII 码表就可以知道。
但如果你用的是课本后面的 ASCII 码表,你会发现,orz,此字符不在表中,越界了! 该表编码的最大值为8进制的 367。那这个字符到底是啥呢?是不是应该模个 2^8? 只要略加计算,就会发现 0367=247,才 247 啊。最大的编码应该是 10 进制的 255 ,再次 OTZ。显然书本后面的表有问题,耐心找一找,就会在表格中发现如下的索引序列 .......266, 267, 260, 261 ......
三、符号扩展
好了,不管它是什么字符了,反正它被编码成 0376,也就是 254。 它当然是个正数!但是为什么又变 -2 了呢? 我有一个猜想:在 16 位编译系统的时代,char 的大小与 short int 是一样,所以编译器的设计者偷了个懒,简单地把它们等同起来。现在虽然已经不是 16 位的时代了,但这个习惯被保留了下来。这就是传统的力量。
基于上述观点, 256 个字符被分成两部分,最高位是 1 的被视为负数。0376 写成二进制是 11111110,最高位是 1, 所以它是负的。它的相反数为 00000001 + 1 = 2,即它就是 -2.
下面我们看一下这个占有 8 位的‘小’ -2 是如何扩展成占有 32 位的 '大‘ -2 的。其实很简单,最高位若为 0,则添加 24 个 0;反之添加 24 个 1。
11111110 -> 111111111111111111111111 11111110
这个规则称为“符号括展”。虽然执行起来简单,但为什么它是合理的呢?不作理论推导,只举两个例子,就已经很清楚了。
如果扩展前的8位数是正的,比如 0123=83,写成 2 进制就是 01010011,前面添 0
01010011 ->000000000000000000000000 01010011
显然扩展后,还是原来的值。
如果原来的是负数,比如二进制 a=10010010,它的相反数是 01101101+1=01101110,即它的值为 -01101110.
a 括展后得到 111111111111111111111111 10010010 它的相反数为
000000000000000000000000 01101101+1=000000000000000000000000 01101110
所以括展之后的数为负的 000000000000000000000000 01101110 ,数值上与负 01101110 是相同的。
四、标准
书本上 -2 的输出是正确的,但它没有指出,这个输出其实是实现相关的。在 INTERNATIONAL STANDARD ©ISO/IEC ISO/IEC 9899:TC2 的 35 页有如下的文字:
The three types char, signed char, and unsigned char are collectively called
the character types. The implementation shall define char to have the same range,
representation, and behavior. as either signed char or unsigned char.
所以 char 有无符号,取决于编译器。
[ 本帖最后由 retuor 于 2009-3-14 17:23 编辑 ] |
|