char、signed char 和 unsigned char 的区别
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;
我们可以看对应的汇编代码:
00BC1505 mov dword ptr [b],0Bh
我们不难发现,数据11(0x0B),在内存中,无论是int还是unsigned int,都是0x0B,存储是一样的,只是解析不同。
2.
C++中的 Integral Promotion发生在算术表达式中(有运算符如+ ~等),其他情况下比如cout语句我要输出一个字符: cout<<a;这个时候不会提升。
3.
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型的。
可以用下面代码小小测试:
cout<<a+0x1;
以及
cout<<a+0x1u;
运行一下,不难看出,0x1被当做int来处理,ox1u才是unsigned int型的。
比较好的参考资料:
这个网址里面对各种数据类型,以及整形提升,Usual Arithmetic Conversion做了非常详细的说明。
char、signed char 和 unsigned char 的区别的更多相关文章
- C语言char*字符串数组和unsigned char[]数组的相互转换
#include <iostream> #include <string> using namespace std; void convertUnCharToStr(char* ...
- C 中 char、signed char 和 unsigned char 的区别
C 中 char.signed char 和 unsigned char 的区别 来源:http://bbs.chinaunix.net/thread-889260-1-1.html 参考:https ...
- signed char、unsigned char
什么是无符号char类型?与常见的char类型有何不同? 在c++中有三种不同的字符类型:char,signed char,unsigned char.如果要应用与文本字符,就使用不加限制的char类 ...
- 关于 char 和 unsigned char 的区别
首先卖个关子: 为什么网络编程中的字符定义一般都为无符号的字符? char buf[16] = {0}; unsigned char ubuf[16] = { 0 }; 上面两个定义的区别是: ...
- 图像处理中像素点的问题:unsigned char 和 char
以前在做图像处理的时候,一直不太在意这个问题,对图像每个像素点的灰度值,总是认为char也可,unsigned char也可.尽管它们都是8位,但是表示的数的范围却不相同:char: -128~127 ...
- QString unsigned char* 的转换
QString -> unsigned char* : QString str = "ABCD"; int length = str.length(); unsigned ...
- char , unsigned char 和 signed char 区别
ANSI C 提供了3种字符类型,分别是char.signed char.unsigned char.char相当于signed char或者unsigned char,但是这取决于编译器!这三种字符 ...
- char、signed char、unsigned char的区别总结。
转载地址:http://hi.baidu.com/thewillreigns/blog/item/67e665c4296e69c038db492d.html char 和 unsigned char是 ...
- char, signed char, and unsigned char in C++
关于这三者的区别stackoverrflow里有一个答案是这样说的: 3.9.1 Fundamental types [basic.fundamental] 1 Objects declared as ...
随机推荐
- Java学习之位运算和逻辑运算符
今天看了一下HashMap类的源码,在HashMap的源码中定义了初始空间的大小 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 当 ...
- Median of Two Sorted Arrays-分治法
题目意思很简单将两个有序数组合并之后的中位数找出来.题目要求使用log(m+n)的时间复杂度来做. 虽然言简意赅,但不得不承认这个题目我自己想了好久也没做出来,隐约觉得应该使用寻找第k大数的算法来做, ...
- java覆写hashcode方法
覆写hashcode 1. 把某个非零常数值,例如17,保存在int变量result中: 2. 对于对象中每一个关键域f(指equals方法中考虑的每一个域): 3, boolean型,计算(f? 0 ...
- JavaScript基础知识----document对象
对象属性document.title //设置文档标题等价于HTML的<title>标签document.bgColor //设 ...
- poj 1604 Just the Facts
/** 大意: 求n! 结果 从左到右 第一个非零数 跟 1150 差不多.. **/ #include <iostream> #include <cstdio> using ...
- 块元素block,内联元素inline; inline-block;
block:块元素的特征 div ol li 等: 1.只有高度不设置宽度的时候默认撑满一行: 2.默认块元素不在一行: 3.支持所以CSS命令: inline:内联元素的特征 span i stro ...
- Apache的Mod_rewrite学习(RewriteRule重写规则的语法)
URL:http://www.tenwe.com/tech/web/server/200705/content_1548.shtml 今天学习重写规则的语法.RewriteRuleSyntax: Re ...
- Test class should have exactly one public zero-argument constructor
java.lang.Exception: Test class should have exactly one public zero-argument constructor at org.juni ...
- BZOJ 1677: [Usaco2005 Jan]Sumsets 求和
题目 1677: [Usaco2005 Jan]Sumsets 求和 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 617 Solved: 344[Su ...
- Uva 552 Prime Ring Problem(dfs)
题目链接:Uva 552 思路分析:时间限制为3s,数据较小,使用深度搜索查找所有的解. 代码如下: #include <iostream> #include <string.h&g ...