回 帖 发 新 帖 刷新版面

主题:以16进制打印unsigned char的问题

代码如下:

#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个回复)

沙发

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]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 楼

[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 楼

两位高手答得好!!

5 楼


谢谢windy0will的回答。
但你说的是数据类型强制转换的规则,我是想知道为什么要做这个强制转换呢?
如果是双目运算符,参与运算的变量会根据数据类型做强制转换,这个我可以理解。
但是我的直接用printf直接打印的一个char,中间没有经过运算。为什么也会做一个
从char到int的强制转换呢?

6 楼

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 楼

谢谢windy0will的回答。这个帖子都有半年时间了,但今天突然有个地方想不通了。不用printf打印char类型的值时也会有同样的问题,所以我认为不是由于printf时的类型转换造成的上面这个问题。代码如下。

char a=0xf0;
if (0xfffffff0 == a)
{
   printf("a is %x\n",a); 
}

上面代码中的printf语句会执行,足以证明不是由于printf时的强制转换造成的0xf0打印出来却是0xfffffff0。但究竟是什么原因造成的,还是希望那位大虾回答下。当然我也不说前面的大虾们回答得不好,只是因为我没有真正理解到当中的意思。

8 楼

0xfffffff0 == a
1、这是一个逻辑表达式。
2、一个变量或常量在一个表达式中会自动向高看齐:)

因为0xfffffff0是长整型(这个是根据数的大小来决定的)
所以这句话产生了隐式类型转换,相当于:
0xfffffff0L == int(a)
当然,如果你写成:
0xfffffff0U == a
那式子就会变成:
0xfffffff0U == unsigned int(a)
这时就不成立了:)

9 楼

谢谢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 楼

[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).
  

我来回复

您尚未登录,请登录后再回复。点此登录或注册