C printf从字符数组向十六进制打印添加额外的“FFFFFF”
考虑下面的简化代码。我想从文件中提取一些二进制数据/流,并以十六进制格式将其打印到标准输出 我得到了额外的3个字节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
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
.PlainCHAR
用于字符串。@cremno它实际上取决于系统,PlainCHAR
可以是有符号的,也可以是无符号的。标准警告:不要将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 );