ANSI C 提供了3种字符类型,分别是char、signed char、unsigned char.而不是像short、int一样只有两种(int默认就是signed 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标准中对此是 Implementation 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 。是不是发现了什么了呢?

首 先,介绍 Integral 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,也就不用 Integral 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。

1.
C++中内置数据类型分为两类:整数、浮点数。 对于不同的整数类型来说,比如int,unsigned int,有这么两句话:
int a=11;
unsigned int b=11;
我们可以看对应的汇编代码:

00BC14FE  mov         dword ptr [a],0Bh  
00BC1505  mov         dword ptr [b],0Bh
我们不难发现,数据11(0x0B),在内存中,无论是int还是unsigned int,都是0x0B,存储是一样的,只是解析不同。 

2.
C++中的 Integral Promotion发生在算术表达式中(有运算符如+ ~等),其他情况下比如cout语句我要输出一个字符:  cout<<a;这个时候不会提升。
3.

Integral Promotion反映在汇编上就是指令 movsx 和movzx。比如一个char型,提升时就会用movsx指令,unsigned char 提升时用movzx指令。
4.本文原作者说常量是无符号数,这种说法值得商榷,《C++ primer》中说过,20,024,0x14的类型是int或者long!!!我想原作者的意思是这样的:
int a=-1; 这句话执行的结果是 a里面存放着:0x FFFFFFFF,也就是-1对应的补码
int a=1  ;  这句话执行的结果是 a里面存放着:0x 00000001,也就是1对应的补码
int a=0xF7;这句话执行结果是 a里面存放着:0x 000000F7,a的低位放着F7,其他高位全部置为0;看起来像是oxF7是无符号数才会按0扩展,但事实上不是这个原因。
本质原因是汇编的mov指令:
mov ax,-1;其实汇编器最终会解释成:mov ax,FFFF
mov ax,F7H;其实汇编器最终会解释成: mov ax,00F7
所以需要注意:  常量-1,3,0xf4都是int或者long型的。
可以用下面代码小小测试:

int a=-3;
cout<<a+0x1;
以及

int a=-3;
cout<<a+0x1u;
运行一下,不难看出,0x1被当做int来处理,ox1u才是unsigned int型的。

比较好的参考资料:

http://book.51cto.com/art/200912/166574.htm
这个网址里面对各种数据类型,以及整形提升,Usual Arithmetic Conversion做了非常详细的说明。

char、signed char 和 unsigned char 的区别的更多相关文章

  1. C语言char*字符串数组和unsigned char[]数组的相互转换

    #include <iostream> #include <string> using namespace std; void convertUnCharToStr(char* ...

  2. C 中 char、signed char 和 unsigned char 的区别

    C 中 char.signed char 和 unsigned char 的区别 来源:http://bbs.chinaunix.net/thread-889260-1-1.html 参考:https ...

  3. signed char、unsigned char

    什么是无符号char类型?与常见的char类型有何不同? 在c++中有三种不同的字符类型:char,signed char,unsigned char.如果要应用与文本字符,就使用不加限制的char类 ...

  4. 关于 char 和 unsigned char 的区别

    首先卖个关子: 为什么网络编程中的字符定义一般都为无符号的字符?   char buf[16] = {0}; unsigned char ubuf[16] = { 0 };   上面两个定义的区别是: ...

  5. 图像处理中像素点的问题:unsigned char 和 char

    以前在做图像处理的时候,一直不太在意这个问题,对图像每个像素点的灰度值,总是认为char也可,unsigned char也可.尽管它们都是8位,但是表示的数的范围却不相同:char: -128~127 ...

  6. QString unsigned char* 的转换

    QString -> unsigned char* : QString str = "ABCD";  int length = str.length(); unsigned ...

  7. char , unsigned char 和 signed char 区别

    ANSI C 提供了3种字符类型,分别是char.signed char.unsigned char.char相当于signed char或者unsigned char,但是这取决于编译器!这三种字符 ...

  8. char、signed char、unsigned char的区别总结。

    转载地址:http://hi.baidu.com/thewillreigns/blog/item/67e665c4296e69c038db492d.html char 和 unsigned char是 ...

  9. char, signed char, and unsigned char in C++

    关于这三者的区别stackoverrflow里有一个答案是这样说的: 3.9.1 Fundamental types [basic.fundamental] 1 Objects declared as ...

随机推荐

  1. 多条件搜索拼接Sql语句

    1. 如下实例:     1.1 如下图所示:[通过用户输入的数据拼接Sql搜索语句]                  1.2         private void button2_Click( ...

  2. Arduino 跷跷板(2016-01-04)

    前言这是参加社区活动,用赠送的 LilyPad 来做小实验,也体验了一把艺术的LilyPad!本来是申请 nano 的,不知道怎么的就出错啦,申请成 LilyPad 了,这个实验应该用 nano 比较 ...

  3. win7 64下安装mysql-python报错的解决办法

    最近要使用django进行项目开发,需要使用mysql-python模块. 在本地搭建环境安装的时候却出现报错,Unable to find vcvarsall.bat  在网上找了很多资料,发现是w ...

  4. 删除缓存内容----unrecognized selector sent to instance

    这条错误主要还得看unrecognized前面,,我的时[NSNumber-length...]其实是变量类型错误.. 无法识别选择器发送实例,,本来意思就是你的controllerview找不到视图 ...

  5. 更改firefox默认搜索引擎

    使用Organizie Search Engines 这个插件  这个插件似乎不能添加搜索引擎 但是可以修改搜索引擎 好吧 由于有时候firefox会自动更新搜索引擎  所以不要对Google搜索引擎 ...

  6. sql server单表导入、导出

    sql server单表导入.导出(通过CSV文件) 导出:直接打开查询分析器查询要导出表的信息(select *  from 表),得到的结果全选,右键另存为 xxx.csv文件  (得到该表的所有 ...

  7. os.path.exists(path) 和 os.path.lexists(path) 的区别

    使用os.path.exists()方法可以直接判断文件是否存在.代码如下:>>> import os>>> os.path.exists(r'C:\1.TXT') ...

  8. BZOJ 1644: [Usaco2007 Oct]Obstacle Course 障碍训练课

    题目 1644: [Usaco2007 Oct]Obstacle Course 障碍训练课 Time Limit: 5 Sec  Memory Limit: 64 MB Description 考虑一 ...

  9. 权限管理之基于ACL的实现:自定义JSTL函数实现即时认证

    实现即时认证(即只有拥有相应的权限,才能做相应的操作) 经常用在,在JSP页面上,调用JSTL自定义函数做判断,显示相应的菜单或者功能按钮,比如只有管理员登陆时才显示“删除”按钮,从而完成权限的即时认 ...

  10. 引入工程报包导入异常:import javax.servlet.annotation.WebFilter;

    引入工程报包导入异常:import javax.servlet.annotation.WebFilter; (2013-02-21 16:38:00)   分类: java 今天上午导入了一个项目,用 ...