【C语言笔记】【陷阱系列】 打印输出问题

【C语言笔记】【陷阱系列】 打印输出问题

陷阱系列内容。用于记录各式各样有陷阱的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, like unsigned char.

Each kind of machine has a default for what char should be. It is either like unsigned char by default or like signed char by default.

Ideally, a portable program should always use signed char or unsigned char when it depends on the signedness of an object. But many programs have been written to use plain char 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 of signed char or unsigned 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, like signed 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

你可能感兴趣的:(C语言笔记,c语言,笔记,c++)