主题:以16进制打印unsigned char的问题
mars51
[专家分:60] 发布于 2011-01-28 00:06:00
代码如下:
#include <stdio.h>
int main(int argc,char *argv[])
{
unsigned char a[2];
char b[2];
a[0] = 0x7f;
a[1] = 0xf0;
b[0] = 0x7f;
b[1] = 0xf0;
printf("a[0] is %02x\n",a[0]);
printf("a[1] is %02x\n",a[1]);
printf("b[0] is %02x\n",b[0]);
printf("b[1] is %02x\n",b[1]);
printf("c is %02x\n",c);
}
下面是执行结果
[root@localhost unsigned char]# ./a.out
a[0] is 7f
a[1] is f0
b[0] is 7f
b[1] is fffffff0
我的问题是:我不是很明白变量b[1](char型,值为0xf0),以%02x方式打印出来为什么是fffffff0。我可以肯定和类型转换有关系,b[1]到最后肯定被转换成了int型,但不能完全搞清楚当中的原因。请各位指教哈
回复列表 (共13个回复)
沙发
bruceteen [专家分:42660] 发布于 2011-01-28 08:22:00
0xf0(char) 压入函数参数栈 是不是就变成了 0xfffffff0(int) ?
假如你还不能理解,可以这么想:
b[1] = 0xf0; 也就是 b[1] = -16;
int param = b[1]; 此时 param 是不是应该等于 -16 ?
int类型的-16是不是就是 0xfffffff0 ?
按照C语言标准,你应该将 %02x 改为 %02hhx,也就是加两个 h
但假如你用的是比较垃圾的VC,那就只能用 printf("b[1] is %02x\n",(unsigned char)b[1]); 了
板凳
mars51 [专家分:60] 发布于 2011-01-28 14:30:00
[quote]0xf0(char) 压入函数参数栈 是不是就变成了 0xfffffff0(int) ?
假如你还不能理解,可以这么想:
b[1] = 0xf0; 也就是 b[1] = -16;
int param = b[1]; 此时 param 是不是应该等于 -16 ?
int类型的-16是不是就是 0xfffffff0 ?
按照C语言标准,你应该将 %02x 改为 %02hhx,也就是加两个 h
但假如你用的是比较垃圾的VC,那就只能用 printf("b[1] is %02x\n",(unsigned char)b[1]); 了[/quote]
谢谢bruceteen的回复。
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
b[1] = 0xf0; 也就是 b[1] = -16;
int param = b[1]; 此时 param 是不是应该等于 -16 ?
int类型的-16是不是就是 0xfffffff0 ?
/*<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
上面这个我理解,但还是没明白你所说的
[color=0000FF]0xf0(char) 压入函数参数栈 是不是就变成了 0xfffffff0(int) ?[/color]
还有,按照你上面的说法
0x7f(unsigned char) 压入函数参数栈后该是多少呢。是否和打印值0x7f相符呢。
3 楼
windy0will [专家分:2300] 发布于 2011-01-28 16:48:00
[quote]
谢谢bruceteen的回复。
/*>>>>>>>>>>>>>>>>>>>>>>>>>>>*/
b[1] = 0xf0; 也就是 b[1] = -16;
int param = b[1]; 此时 param 是不是应该等于 -16 ?
int类型的-16是不是就是 0xfffffff0 ?
/*<<<<<<<<<<<<<<<<<<<<<<<<<<<*/
上面这个我理解,但还是没明白你所说的
[color=0000FF]0xf0(char) 压入函数参数栈 是不是就变成了 0xfffffff0(int) ?[/color]
还有,按照你上面的说法
0x7f(unsigned char) 压入函数参数栈后该是多少呢。是否和打印值0x7f相符呢。[/quote]
一般而言,
1.如果是signed类型,类型升级时如果最高位是1则在高位填充1;否则填充0
如signed char sc = 0xf0要转换成signed int,因为0xf0的最高位是1,那么将转换为0xfffffff0.
而signed char sc = 0x70要转换成signed int,因为0x70最高位是0,那么将转换为0x00000070.
2.如果是unsigned类型,类型提升时总是在高位填充0
如unsigned char uc = 0xf0要转换成unsigned int, 转换结果是 0x000000f0
int默认的是signed int;char默认的是signed char.unsigned默认是unsigned int.
a. 如果表达式中有unsigned类型的,则需把各操作数转换成unsigned。
b. 如果表达式有int类型和char类型,则把char的类型转换成int类型。
如果同时有a和b的情况,要先考虑b.我举个例子:
signed char c = 0xf0; 考虑:int i = (unsigned int)c;和int i = (unsigned)c
首先按b转换 把c(signed char)转换成signed int类型为 0xfffffff0;
然后再把signed int型的0xfffffff0转换为unsigned int型的0xfffffff0.
但如果有signed char c = 0xf0;
int i = (unsigned char)c;这样的话将得到的结果是 i == 0xf0;
4 楼
强强 [专家分:4740] 发布于 2011-01-28 22:12:00
两位高手答得好!!
5 楼
mars51 [专家分:60] 发布于 2011-01-29 22:17:00
谢谢windy0will的回答。
但你说的是数据类型强制转换的规则,我是想知道为什么要做这个强制转换呢?
如果是双目运算符,参与运算的变量会根据数据类型做强制转换,这个我可以理解。
但是我的直接用printf直接打印的一个char,中间没有经过运算。为什么也会做一个
从char到int的强制转换呢?
6 楼
windy0will [专家分:2300] 发布于 2011-01-30 18:16:00
printf系列函数:%d,%i等这几个格式默认接受的是int类型。前面加一个h表示将参数转为short,两个h转为char,一个l转为long; %x,%X,%O,%o,%u则默认为unsigned。C99标准还添加了一些新格式和类型修饰, 不过目前很多编译器都没实现的比较好。如%a是把一个浮点数按十六进制打印,反正我目前用的GCC版本是不支持的。
还有一点,printf是一个可变参函数。它的参数个数是可变的。可变参函数对某些类型是有类型提升的。如float会自动转为double。(char,short会不会转为int我忘了,我想应该也会自动转的,您最好用GCC编译成汇编代码来确认下)。我觉得:char自动转为int是在进入printf以前就完成的,即使用%hhd也是在printf函数里面完成的。
7 楼
mars51 [专家分:60] 发布于 2011-07-20 22:43:00
谢谢windy0will的回答。这个帖子都有半年时间了,但今天突然有个地方想不通了。不用printf打印char类型的值时也会有同样的问题,所以我认为不是由于printf时的类型转换造成的上面这个问题。代码如下。
char a=0xf0;
if (0xfffffff0 == a)
{
printf("a is %x\n",a);
}
上面代码中的printf语句会执行,足以证明不是由于printf时的强制转换造成的0xf0打印出来却是0xfffffff0。但究竟是什么原因造成的,还是希望那位大虾回答下。当然我也不说前面的大虾们回答得不好,只是因为我没有真正理解到当中的意思。
8 楼
cgl_lgs [专家分:21040] 发布于 2011-07-21 10:54:00
0xfffffff0 == a
1、这是一个逻辑表达式。
2、一个变量或常量在一个表达式中会自动向高看齐:)
因为0xfffffff0是长整型(这个是根据数的大小来决定的)
所以这句话产生了隐式类型转换,相当于:
0xfffffff0L == int(a)
当然,如果你写成:
0xfffffff0U == a
那式子就会变成:
0xfffffff0U == unsigned int(a)
这时就不成立了:)
9 楼
mars51 [专家分:60] 发布于 2011-07-22 15:04:00
谢谢cgl_lgs的回答,但我按你的说方法跑了下,结果和你的说法不一样哈。无论是0xfffffff0L == a或0xfffffff0U == a。结论是都成立。
1 #include <stdio.h>
2 int main()
3 {
4 char a=0xf0;
5 if (0xfffffff0 == a){
6 printf("%d:a is %02x\n",__LINE__,a);
7 }
8 if (0xfffffff0L == a){
9 printf("%d:a is %02x\n",__LINE__,a);
10 }
11 if (0xfffffff0U == a){
12 printf("%d:a is %02x\n",__LINE__,a);
13 }
14 return 0;
15 }
[root@localhost unsigned char]# ./a.out
6:a is fffffff0
9:a is fffffff0
12:a is fffffff0
10 楼
windy0will [专家分:2300] 发布于 2011-07-22 16:25:00
[quote]
char a=0xf0;
if (0xfffffff0 == a)
{
printf("a is %x\n",a);
}
上面代码中的printf语句会执行,足以证明不是由于printf时的强制转换造成的0xf0打印出来却是0xfffffff0。但究竟是什么原因造成的,还是希望那位大虾回答下。当然我也不说前面的大虾们回答得不好,只是因为我没有真正理解到当中的意思。[/quote]
这里if里面的语句肯定会执行:
a 是 signed char类型,
1.if (0xfffffff0 == a)等价于if (0xfffffff0 == (signed int)a),
2.(signed int)a转换后的结果刚好是 0xfffffff0(因为a的最高位是1)
而 printf("a is %x\n",a);等价于printf ("a is %x\n", (int)a);
这是由于1.printf函数最开始不知道%x需要的的是unsigned类型,
2.而传给它的参数a是signed char 类型,(由于printf是可变参函数,
故将会有类型提升,a被转为0xfffffff0(signed int).
3.但是进入printf后,遇到%x这个格式,这个格式将再把那个
signed int类型的数0xffffff0转换为0xfffffff0(usngiend int).
我来回复