C语言关于char类型%02X的输出问题分析
1 问题描述
在与加密机进行交互的时候,原程序从AIX系统迁移到LINUX系统,密码解密一直失败,经过排查发现使用sprintf对bcd码进行asc码的转换,发现转换出来的asc码加密机无法解析,有很多FFFF的情况。
排查程序发现并未用标准的bcd_to_asc函数,但是这样转换一般情况下没有问题。
将程序简化代码如下,
#include
#include
#include
int main()
{
char bcd[9];
char asc[30];
bcd[0]= 0x8D;
bcd[1]= 0x2D;
bcd[2]= 0x3D;
bcd[3]= 0x4D;
bcd[4]= 0x5D;
bcd[5]= 0x6D;
bcd[6]= 0x7D;
bcd[7]= 0x8D;
sprintf( asc, "%02X%02X%02X%02X%02X%02X%02X%02X", bcd[0], bcd[1], bcd[2], bcd[3], bcd[4], bcd[5], bcd[6], bcd[7]);
printf( "%s,%ld\n", asc, strlen(asc));
return 0;
}
/** 运行结果 **
FFFFFF8D2D3D4D5D6D7DFFFFFF8D,28
**/
2 问题分析
怀疑是%02X输出的有问题,增加日志查看如下:
#include
#include
#include
int main()
{
char bcd[9];
unsigned char u_bcd[9];
char asc[30];
bcd[0]= 0x8D;
bcd[1]= 0x2D;
bcd[2]= 0x3D;
bcd[3]= 0x4D;
bcd[4]= 0x5D;
bcd[5]= 0x6D;
bcd[6]= 0x7D;
bcd[7]= 0x8D;
strcpy( u_bcd, bcd);
sprintf( asc, "%02X%02X%02X%02X%02X%02X%02X%02X", bcd[0], bcd[1], bcd[2], bcd[3], bcd[4], bcd[5], bcd[6], bcd[7]);
printf( "%s,%ld\n", asc, strlen(asc));
sprintf( asc, "%02X%02X%02X%02X%02X%02X%02X%02X", u_bcd[0], u_bcd[1], u_bcd[2], u_bcd[3], u_bcd[4], u_bcd[5], u_bcd[6], u_bcd[7]);
printf( "%s,%ld\n", asc, strlen(asc));
sprintf( asc, "%d %d %d %d %d %d %d %d", bcd[0], bcd[1], bcd[2], bcd[3], bcd[4], bcd[5], bcd[6], bcd[7]);
printf( "%s,%ld\n", asc, strlen(asc));
sprintf( asc, "%d %d %d %d %d %d %d %d", u_bcd[0], u_bcd[1], u_bcd[2], u_bcd[3], u_bcd[4], u_bcd[5], u_bcd[6], u_bcd[7]);
printf( "%s,%ld\n", asc, strlen(asc));
return 0;
}
/** 运行结果 **
FFFFFF8D2D3D4D5D6D7DFFFFFF8D,28
8D2D3D4D5D6D7D8D,16
-115 45 61 77 93 109 125 -115,29
141 45 61 77 93 109 125 141,27
**/
通过运行结果分析,问题已经很明显了。
unsigned char
是无符号的,char
是有符号的,也就是char
只有7bit长,0x80开始,已经占用了第8位,这时候char
类型会认为已经进行了补码运算,就是负数。
而%02X的输入情况如下:
- %X输出,会把后面认为是
int
,所以当为负数的时候,会进行补码
运算,后续进行FFFFFF
是对int
类型补码的结果. - 02只能限定不足2位补齐两位,不能限定只输出2位(实际上只输出两位也是不正确的,会输出FF)