C++之char , signed char , unsigned char

来源:互联网 发布:无线淘宝 编辑:程序博客网 时间:2024/04/29 15:45

ANSI C 提供了3种字符类型,分别是charsigned charunsigned 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;

 if ( a == 0xb6) puts("hello world !");

在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)。比如  “a == 0xb6”,首先0xb6会当一个int来处理,变为0x000000b6(关于常量,后面还会仔细说明)。a 会提升为int ,假如 char 被定义为有符合的,那么 a 为负数,因为最高位为1,所以 a会提升为 0xffffffb6。假如 char 被定义为无符号的,那么a会提升为0x000000b6 。

即,在vc 或 x86的gcc 上,(a == 0xb6) 会变为 (0xffffffb6 == 0x000000b6) ,而在 arm-linux-gcc 上,变为(0x000000b6 == 0x000000b6)。

对于 short,因为c标准明确规定 不加关键字,就代表有符号数。所以,无论在什么编译器上 b == 0xb600 都会变成 0xffffb600 == 0x0000b600 。

对于 int,本身是int,也就不用 Integer Promotion 了,所以  c == 0xb60000 中 ,c不做任何处理,直接从内存中读出来,即  0xb60000 == 0xb60000。

最后,简单说一下常量。用八进制(0开头)或十六进制(0x开头)表示的常量,他们都会当成无符号数处理! 另外 像 char a = 0xb6; 这句就有两个 Implementation Defined,一个是char带不带符号,另外一个是,假如char为有符号, 0xb6 会当int 0x000000b6 处理,把这个int 变为 有符号的 char 有溢出,会有问题,0xb6本为正数,赋值到a中却变为负数,具体要怎么处理,c对此也是 Implementation Defined。
0 0
原创粉丝点击