printf将额外的'FFFFFF'从字符数组添加到十六进制打印[duplicate]

ocebsuys  于 2023-01-25  发布在  其他
关注(0)|答案(3)|浏览(165)
    • 此问题在此处已有答案**:

Why does printf not print out just one byte when printing hex?(5个答案)
六年前关闭了。
考虑下面的简化代码。我想从一个文件中提取一些二进制数据/流,并将其以十六进制格式打印到标准输出。
我得到了额外的3个字节0xFFFFFF。怎么了?额外的字节是从哪里来的?

    • 输出**
in:
        2000FFFFFFAF00690033005A00
out:
        2000FFFFFFAF00690033005A00
    • 程序. c**
#include <stdio.h>
#include <stdlib.h>    

int main(int argc, char** argv) {

    int i;
    char raw[10] = {0x20,0x00,0xAF,0x00,0x69,0x00,0x33,0x00,0x5A,0x00};
    FILE *outfile;
    char *buf;

    printf("in:\n\t");
    for( i=0; i<10; i++ )
        printf("%02X", raw[i]);

    outfile = fopen("raw_data.bin", "w+b");

    fwrite(raw, 1, 10, outfile);

    buf = (char *) malloc (32 * sizeof(char));
    fseek(outfile, 0, SEEK_SET);
    fread(buf, 1, 10, outfile);

    printf("\nout:\n\t");
    for( i=0; i<10; i++ )
        printf("%02X", buf[i]);

    printf("\n");

    fclose(outfile);
    return 0;
}
r6l8ljro

r6l8ljro1#

符号扩展。您的编译器将char实现为signed char。当您将字符传递给printf时,它们在提升为int s的过程中都会进行符号扩展。当第一位为0时,这并不重要,因为它会使用0 s进行扩展。
0xAF在二进制中是10101111由于第一位是1,当将其传递给printf时,在转换为int的过程中,它将扩展为所有1,使其成为11111111111111111111111110101111,即0xFFFFFFAF,即您所拥有的十六进制值。

**解决方案:**使用unsigned char(而不是char)防止在调用中发生符号扩展

const unsigned char raw[] = {0x20,0x00,0xAF,0x00,0x69,0x00,0x33,0x00,0x5A,0x00};

原始示例中的所有这些值都进行了符号扩展,只是0xAF是唯一一个第一位为1的值。
相同行为的另一个简单示例(live link):

signed char c = 0xAF; // probably gives an overflow warning
int i = c; // extra 24 bits are all 1
assert( i == 0xFFFFFFAF );
bnl4lu3b

bnl4lu3b2#

这是因为0xAF在从有符号字符转换为有符号整数时是负数(它是符号扩展的),而%02X用于无符号参数,并将转换后的值打印为FFFFFFAF
额外字符的出现是因为printf %x * 从不 * 悄悄地从一个值中截断数字。非负值也会得到符号扩展,但这只是添加0位,值适合2个十六进制数字,所以printf %02可以输出2位数字。
请注意,C语言有两种方言:一个是普通的char有符号的,另一个是无符号的。在你的中它是有符号的。你可以用一个选项来改变它,例如gcc和clang支持-funsigned-char-fsigned-char

s1ag04yj

s1ag04yj3#

printf()是一个 * 可变参数 * 函数,其附加参数(对应于其原型的...部分)受 * 默认参数提升 * 的影响,因此char被提升为int
由于您的char具有signed1,two's complement表示形式,因此0xAF元素的最高有效位设置为1。在升级期间,将传播带符号位,从而生成int类型的0xFFFFFFAF,可能与您的实现中的sizeof(int) = 4相同。
顺便说一下,您正在调用undefined behaviour,因为%X说明符应该用于unsigned int类型的对象,或者至少用于MSB未设置的int(这是常见的、广泛接受的做法)。
按照建议,您可以考虑使用明确的unsigned char类型。
1)实现可以在char的有符号和无符号表示之间进行选择。char有符号是相当常见的,但是你不能认为这对地球上的其他编译器来说是理所当然的。其中一些编译器可以允许在这两种模式之间进行选择,就像Jens's answer中提到的那样。

相关问题