C printf从字符数组向十六进制打印添加额外的“FFFFFF”

C printf从字符数组向十六进制打印添加额外的“FFFFFF”,c,arrays,printf,C,Arrays,Printf,考虑下面的简化代码。我想从文件中提取一些二进制数据/流,并以十六进制格式将其打印到标准输出 我得到了额外的3个字节0xFFFFFF。发生了什么?额外的字节是从哪里来的 输出 in: 2000FFFFFFAF00690033005A00 out: 2000FFFFFFAF00690033005A00 程序.c #include <stdio.h> #include <stdlib.h> int main(int argc, cha

考虑下面的简化代码。我想从文件中提取一些二进制数据/流,并以十六进制格式将其打印到标准输出

我得到了额外的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;
}
#包括
#包括
int main(int argc,字符**argv){
int i;
charraw[10]={0x20,0x00,0xAF,0x00,0x69,0x00,0x33,0x00,0x5A,0x00};
文件*输出文件;
char*buf;
printf(“in:\n\t”);

对于(i=0;i,这是因为从有符号字符转换为有符号整数时0xAF为负数(它是符号扩展的),而
%02X
格式用于无符号参数,并将转换后的值打印为
ffffff af

额外字符的出现是因为printf
%x
永远不会自动截断值中的数字。非负数的值也会得到符号扩展,但这只是添加零位,值适合2个十六进制数字,因此printf
%02
可以使用两位数字输出


请注意,有两种C语言:一种是有符号的纯
char,另一种是无符号的。在您的语言中,它是有符号的。您可以使用一个选项来更改它,例如gcc和clang支持
-funsigned char
-fsigned char
符号扩展。您的编译器正在将
char
实现为
有符号的char
。当您将字符传递给
printf
时,在升级到
int
s的过程中,它们都被符号扩展。当第一位为0时,这并不重要,因为它会随着
0
s扩展

二进制文件中的
0xAF
10101111
,因为第一位是
1
,当将它传递给
printf
时,它会在转换为
int
时用所有
1
扩展,使其成为
1111111111111 0101111
,即您拥有的十六进制值


解决方案:使用
unsigned char
(而不是
char
)来防止呼叫中出现符号扩展

const unsigned char raw[] = {0x20,0x00,0xAF,0x00,0x69,0x00,0x33,0x00,0x5A,0x00};
原始示例中的所有这些值都是符号扩展的,只是
0xAF
是唯一第一位有
1
的值

相同行为的另一个简单示例():

printf()
是一个可变函数,其附加参数(对应于其原型的
部分)受默认参数提升的影响,因此
char
被提升为
int

由于您的
char
已签名1,表示法将
0xAF
元素的最高有效位设置为1。在升级过程中,有符号位被传播,从而产生
0xffffaf
int
类型,在您的实现中可能是
sizeof(int)=4

通过调用的方式,由于
%X
格式说明符应用于类型为
无符号int
的对象,或至少用于未设置MSB的
int
(这是常见的、广泛接受的做法)

建议您考虑使用明确的<代码>无符号char < /代码>类型。



(一)实现可以在
char
的有符号和无符号表示之间进行选择。
char
是有符号的,这是很常见的,但您不能将其视为地球上所有其他编译器的理所当然。其中一些编译器可能允许在这两种模式之间进行选择,如中所述。

使用
无符号char
,因为
0xAF>CHAR\u MAX
.Plain
CHAR
用于字符串。@cremno它实际上取决于系统,Plain
CHAR
可以是有符号的,也可以是无符号的。标准警告:不要将
void*
(例如由
malloc()
给出)强制转换到其他指针!还有:
sizeof(CHAR)
永远不会与
1
有所不同,因为这是标准定义要产生的!如果更改类型不是一个选项,只需将其转换为:
printf(“%02X”,(unsigned char)buf[i]);
更改char的签名性并不是一个真正持久的解决方案。。。
signed char c = 0xAF; // probably gives an overflow warning
int i = c; // extra 24 bits are all 1
assert( i == 0xFFFFFFAF );