C中八进制和十六进制转义字符揭秘

c中有一种数值型的转义字符,即’\ddd’的三位八进制转义字符和’\xdd’的两位十六进制转义字符。这两种转移字符其代表着一个字节大小的整数值字符

首先什么是转义字符,顾名思义转义字符最终是一种字符,只不过它是被转义了一下。所以它是一个字符的本质是不会变的。这也就是上面为什么说“这两种转移字符其代表着一个字节大小的整数值字符。”,因为字符是一个字节大小的。它是一个字符,但是由一个整数(三位八进制或两位十六进制)表示,正如ASCII码表中整数值48代表字符’0’一样。只不过’\000’代表整数0,其对应ASCII码表对应的字符为NULL。解释的有点拗口,但是大致的意思就是这样。

其八进制转义字符测试代码8zhuanyi.cpp如下:

01 #include

02 using namespace std;

03

04 #define b '\001'

05

06 int main()

07 {

08 cout<<"8 进制转移字符的sizeof大小:"<

09 int a = b;

10 cout<<"putchar(a): ";

11 putchar(a);

12 cout<

13

14 cout<<"putchar(b): ";

15 putchar(b);

16 cout<

17 printf("b的整数值为:%d\n", b);

18

19 system("pause");

20 return 0;

21 }

其输出打印结果如下:

结论分析:

可以看到,b是一个字符,所以cout<时输出的是一个笑脸,并且b的大小只有一个字节。根据b的内存大小就可以得知b肯定不是一个int整数,而是一个字符。并且b代表的整数值为1,对应为ASCII码表的值。

相同我们也可以看看’\xdd’的两位十六进制转义字符。

其十六进制转义字符测试代码16zhuanyi.cpp如下:

01 #include

02 using namespace std;

03

04 #define b '\x01'

05

06 int main()

07 {

08 cout<<"16 进制转移字符的sizeof大小:"<

09 int a = b;

10 cout<<"putchar(a): ";

11 putchar(a);

12 cout<

13

14 cout<<"putchar(b): ";

15 putchar(b);

16 cout<

17 printf("b的整数值为:%d\n", b);

18

19 system("pause");

20 return 0;

21 }

其输出打印结果如下:

通过上述两个演示代码,我再一次强调“这两种转移字符其代表着一个字节大小的整数值字符。”这一个原理。以下的分析测试可能与这个过程相互映衬。

问题1:超出范围(不能超过9位,即'\201',‘\’跟后数字不能超过4,否则出错,与编译器有关,要么截断,要么编译错误,VC6.0中报错!!有符号整数,-128~127且为补码存储!!)

一个字节八位,八进制转义字符中,而三位的八进制有9位(每一位八进制相当于3位二进制),所以说'\ddd'表示的范围已经超出了一个字节的表示范围!然而这会发生什么了,不妨做一个实验。

8zhuanyi.cpp中第4行的代码#define b '\001'换成#define b '\401'

其输出如下:

通过对比输出可以看到,输出时没有任何变化的。为什么'\001''\401'的输出是一样的?我们将其转换为二进制来看一看。

'\001' 000 000 001

'\401' 100 000 001

而一个字符只有8位,转义字符'\001''\401'都有9位,于是我们情不自禁的就想到“截断”。如果真是截断,那么'\001''\401'所表示的字符的值就是一样的,舍弃了最高位的情况下,所以输出都是1,打印内容一样。

而十六进制转义字符两位十六进制刚好对应8位二进制,表示一个字符的范围,所以不会出现上述问题。

问题2转义字符是否是有符号字符(有符号!!

关于这个问题只需将最高位,即8位置1,观察打印出来的数是否为正数就可以得到答案。修改将8zhuanyi.cpp中第4行的代码#define b '\001'换成#define b '\201'

其输出如下:

可见八进制转移字符是有符号的字符!(包括十六进制转义字符也一样)

问题3:由于八进制中只有“0——7”,如果转义字符中出现“非合法数字”89会怎么办?同样的问题是,’\xdd’十六进制中只有“0——9 A|a——F|f”,如果转义字符中出现了诸如‘G’之类的字符会是什么情况?

这个问题最好的办法就是做一个测试。修改将8zhuanyi.cpp中第4行的代码#define b '\001'换成#define b '\008'

其输出如下:

这个测试的结果就有点异常!首先转义字符的内存大小sizeof变为4而不是1,和int的大小一样。从某种意义上来说'\008'已不再是表示一个字符了,而是一个整数。

其次'\008'的整数值为56,很显然读的是字符’8’ASCII码中的整数值56。而不是像“合法”情况下那样,直接读取的该整数值。所以这里面有一个更深层次也更隐晦的问题,就是'\008'中的8不再表示3位二进制,而是表示8位二进制。因为系统将8作为一个字符’8’来处理了。

为了验证这一点,再做一个测试。修改将8zhuanyi.cpp中第4行的代码#define b '\008'换成#define b '\018'

其输出如下:

对比前后两个输出,不经会发现一个问题。'\018''\018'putchar()都是8。但是其代表的整数值一个是312,而一个是56,这是为什么?

既然都是占4个字节,不妨转化为二进制来看一看。

'\018' 3120000 0000 0000 0000 0000 0001 0011 1000

'\008' 560000 0000 0000 0000 0000 0000 0011 1000

这样我们就不难发现,putchar()函数是输出一个八位二进制的字符,是一个字节。而'\018''\008'都是四个字节,所以在调用putchar()函数时,系统会将其截断,取低8位。所以调用putchar()函数输出的结果都是一样。

这就说明一个问题,当转义字符中出现“非法”的字符89时,系统将会视为ASCII码的八位二进制来处理,因为它会当一个字符来处理,而不是一个数字来处理。而不再是“合法”情况下三位二进制处理。所以这个’8’可以是任意一个字符,诸如’A’等等。

但是上面的输出还有一个问题,解释不了。那就是'\018'为什么1“合法”当数字处理,整数值为1;而8“非法”当字符处理,整数值为56。我们可以这样猜测,系统一开始并不知道转义字符中包含“非法”字符,所以系统“从左往右”读取转移字符时,先是按照正常的,合法的流程处理。先处理0,合法,值为0;接着处理1,也合法,值为1;最后处理8,不合法,所以值为56。拼在一起就是上面的结果

'\018' 3120000 0000 0000 0000 0000 0001 0011 1000

按照这种逻辑下去,又有一个问题需要解释。假设有一种情况'\081',这个1是当“合法”数值处理,还是“不合法”当字符处理,测试一下。

修改将8zhuanyi.cpp中第4行的代码#define b '\018'换成#define b '\081'

其输出如下:

转换为二进制看一看:

'\081' 143850000 0000 0000 0000 0011 1000 0011 0001

56(‘8’) 49(‘1’)

这样可以得知,1是当做“不合法”当字符处理。所以可以得出一个结论,当转移字符中出现了非法字符时,转义字符变为一个4个字节的整数,从左至右,从第一个非法字符开始一直往右的所有字符都被当成“非法”字符处理。包括诸如12之类。这样也主要是因为,其性质已经变了,变成了4个字节大小了。

问题三得出的所有结论,同样适应于十六进制转义字符。因为没有异议,所以就不再做演示代码了。我测试的过程中,两者的结果都是一样的。

问题4:输入的转义字符不是规定的长度,比如’\00’会是什么情况。

对于八进制转义字符而言,不足会补0,超过的话就变为4字节。(char c='\11';printf("%d\n",c);会打印9)

对于十六进制转义字符而言,不足会补0,超过的话也不会变为4字节,它会取最后两位。始终大小为1,除了碰到“非法”字符之外。

char a='\xAG';//正确,将字符'G'赋值给a,去掉G保留A打印整数10,保留G去掉A编译出错!!!!
char a='\xGA';//范围超出,编译出错
printf("%d",a);//打印整数71
cout<<a<<endl;//打印字符G



转自:http://blog.chinaunix.net/uid-23552868-id-191223.html

  • 34
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值