问题:将一个字符类型按16进制输出,输出格式为0xab, 0x后面要求是2位,不够2位则补0,比如“0x0b”。
常见的错误做法是:
#include <stdio.h> int main() { char a = 0x41; // a = 'A' printf( "the hex value of a is 0x%02x\n", a ); return 0; }
貌似正确,但是如果a = 0xf1,上面的输出将是 0xfffffff1 而不是 0xf1。
究其原因,%x 是 unsigned int 或 int 型输出 ,所以 printf("%x", a) 在执行时将自动将 a 类型提升(char 将提升至 int;unsigned char 将提升至 unsigned int), 注意到 char 是 signed(有符号的),如果这时 a 是负数 ,在提升的时候前面将会补1 ,即象反例中的 0xf1 => 0xfffffff1;而unsigned char 在提升的时候只会补0。
解决的办法有三:
方法1. 强制类型转换
#include <stdio.h> int main() { char a = 0xf1; printf( "the hex value of a is 0x%02x\n", (unsigned char)a ); return 0; }
但是上面的例子不能写成 (unsigned int)a 或者 (unsigned short)a。这又涉及到类型隐式转换的过程,举例来说:
当 a 是 char,(unsigned int)a 提升的过程: char => int int => unsigned int
方法2. 精确打印格式
#include <stdio.h> int main() { char a = 0xf1; printf( "the hex value of a is 0x%02hhx\n", a ); return 0; }
其中 hh 将会将 int 转化成 char;unsigned int 转化成 unsigned char。具体可以 man 3 printf 查看详情。
hh A following integer conversion corresponds to a signed char or unsigned char argument, or a following n conversion corresponds to a pointer to a signed char argument.
注意:printf format 格式与平台相关( linux 中的 printf 在 glibc 中实现 ),方法2在 VC 并不能通过。
方法3. 强制位数为 1 byte
#include <stdio.h> int main() { char a = 0xf1; printf( "the hex value of a is 0x%02x\n", (a&0xff) ); return 0; }
上面隐含过程是:先将 char a 提升至 int,然后再与 0xff 相与。