陷阱系列内容。用于记录各式各样有陷阱的C语言情况☺。
有时候我们需要打印一些16进制数,例如下面的代码:
int main(int argc, char* argv[])
{
char buf[] = {0x12, 0x34, 0x56, 0x78, 0x80, 0xab, 0xcd, 0xef};
for(int i = 0; i < sizeof(buf)/sizeof(char); i++) {
printf("0x%x\n", buf[i]);
}
printf("\n");
return 0;
}
代码运行后的结果如下:
0x12
0x34
0x56
0x78
0xffffff80
0xffffffab
0xffffffcd
0xffffffef
发现有些数据正常输出,有些数据就不太正常,高位都置1了,全都变成了0xff,这是为什么呢?
printf
中的转换类型代码 x,X,是以16进制输出的 unsigned int 类型,而上述的代码中 buf 的值是 char 类型,而 char 类型到底是有符号还是无符号类型,取决于编译器,所以可能像是 signed char 或者像是 unsigned char 。我使用的平台,char 类型相当于 signed char,所以是有符号类型,signed char 转换成 unsigned int,如果是负数,也就是最高位为 1 的数,例如0x80, 0xab,转换成 unsigned int 时,会将高位全部补1,也就变成了 0xffffff80, 0xffffffab这样的数了。
很多人可能不知道,字符类型其实是有3种的,分别为 char , signed char 和 unsigned char。
在 C89 中的 3.1.2.5 Types
There are three character types, designated as char , signed char , and unsigned char.
所以 char 类型到底是有符号还是无符号类型,取决于编译器。
那么要怎么解决这个问题呢?
一种是在数据打印输出时,将要输出的数据buf[i]
强制转换为unsigned char
类型,变为(unsigned char)buf[i]
,如下:
int main(int argc, char* argv[])
{
char buf[] = {0x12, 0x34, 0x56, 0x78, 0x80, 0xab, 0xcd, 0xef};
for(int i = 0; i < sizeof(buf)/sizeof(char); i++) {
printf("0x%x\n", (unsigned char)buf[i]);
}
printf("\n");
return 0;
}
这样输出就正常了:
0x12
0x34
0x56
0x78
0x80
0xab
0xcd
0xef
另一种方法是不要使用char
类型,而是使用unsigned char
类型来定义数据,例如定义buf
时变为unsigned char buf[]
,如下:
int main(int argc, char* argv[])
{
unsigned char buf[] = {0x12, 0x34, 0x56, 0x78, 0x80, 0xab, 0xcd, 0xef};
for(int i = 0; i < sizeof(buf)/sizeof(char); i++) {
printf("0x%x\n", buf[i]);
}
printf("\n");
return 0;
}
这样输出就是正常了。
如果是使用GCC编译,则加入编译选项-funsigned-char
,让char
类型变成无符号类型,就像unsigned char
一样。
在GNU中关于编译选项-funsigned-char
的说明如下:
-funsigned-char
Let the type
char
be unsigned, likeunsigned char
.Each kind of machine has a default for what
char
should be. It is either likeunsigned char
by default or likesigned char
by default.Ideally, a portable program should always use
signed char
orunsigned char
when it depends on the signedness of an object. But many programs have been written to use plainchar
and expect it to be signed, or expect it to be unsigned, depending on the machines they were written for. This option, and its inverse, let you make such a program work with the opposite default.The type
char
is always a distinct type from each ofsigned char
orunsigned char
, even though its behavior is always just like one of those two.
也可以使用编译选项-fno-signed-char
,这个是编译选项-fsigned-char
的否定形式,所以-fno-signed-char
和编译选项-funsigned-char
是等价的。
如果使用的平台没有遇见这个问题,也可以使用编译选项-fsigned-char
或者-fno-unsigned-char
来感受下这个问题,让char
类型变成有符号类型,就像char
一样☺。
-fsigned-char
Let the type
char
be signed, likesigned char
.Note that this is equivalent to -fno-unsigned-char, which is the negative form of -funsigned-char. Likewise, the option -fno-signed-char is equivalent to -funsigned-char.
C和指针
The C89 Draft
ISO/IEC 9899:1999
ISO/IEC 9899:201x
3.4 Options Controlling C Dialect
本文链接:https://blog.csdn.net/u012028275/article/details/130998171