ANSI C 提供了3种字符类型,分别是char、signed char、unsigned char.而不是像short、int一样只有两种(int默认就是unsigned int).
三者都占1个字节(1 byte),因此:
signed char取值范围是 -128 到 127(有符号位)
unsigned char 取值范围是 0 到 255
这个大家都很清楚!!
但是char 呢?范围是多少?
答案是:不一定!!!
我们先看一下大师们怎么说的:
(Thinking in C++ 2nd):
signed is the default and is only necessary with char; char may or may not default to signed. By specifying signed char, you force the sign bit to be used.
译文:有符号类型是默认(指的是对于其他整型如int等来说)的类型并且仅对于char来说才是必须的。char有可能是signed也有可能是unsigned(我想这可能取决于编译器的具体实现)。但通过显式地指定一个char为signed,你就迫使其成为有符号的字符型。
我的看法是:
我们首先从这些类型的用处开始想起!
char是用来声明字符的!
而signed char和unsigned char是用来声明数值的,和int与unsigned int一样,只是其占据的空间少(这在手机等空间有限的嵌入式系统中尤其有效!),表示的范围有限。
那么char在各个编译器中是怎样实现的?
c标准中对此是 Impementation Defined,就是未明确定义,由具体的编译器明确定义。
但是一般都是用signed char或unsigned char来实现char的,因为这三种类型的对象在存储介质中的表现形式是一样的(都是一个占8bit的01串,只是解析的时候不同)。
至于到底是signed char还是unsigned char,各个编译器不同!!VC编译器、x86上的GCC都把char定义为signed char,而arm-linux-gcc却把char定义为 unsigned char.
这样一来,在代码移植(困扰我们程序员的一个问题)上就会出现问题,举个最简单的例子:
char a = 0xb6;
在vc 或 x86的gcc 上,都是不会打印出 hello world! 的。
用 arm-linux-gcc 编译,在arm板上,是可以打印出hello world ! 的。
我们再变化一下:
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if ( a == 0xb6) puts("a");
if ( b == 0xb600) puts("b");
if ( c == 0xb6000000) puts("c");
在vc 或 x86的gcc 上,只会打印出 c 。用 arm-linux-gcc 编译,在arm板上,是可以打印出 a 和 c 。是不是发现了什么了呢?
首先,介绍 Integer Promotion(整数提升) 。通俗点说,c在处理整型(char short int)时,都会自动提升为int(如果int范围不够,则提升成 unsigned int)。比如
即,在vc 或 x86的gcc 上,(a == 0xb6) 会变为 (0xffffffb6 == 0x000000b6) ,而在 arm-linux-gcc 上,变为(0x000000b6 == 0x000000b6)。
对于 short,因为c标准明确规定 不加关键字,就代表有符号数。所以,无论在什么编译器上 b == 0xb600 都会变成 0xffffb600 == 0x0000b600 。
对于 int,本身是int,也就不用 Integer Promotion 了,所以