一、出现问题
#include <stdio.h>
typedef struct {
char cBitL : 4,
cBitH : 4;
} charBit;
int main() {
charBit test;
test.cBitL = 0x1;
test.cBitH = 0x4;
printf("charBit size is %u\n", sizeof(test)); // 打印1号
printf("charBit test castInt is %d\n", test); // 打印2号
printf("charBit test castChar is %c\n", test);
printf("charBit test is 0x%x\n", test);
return 0;
}
在CodeBlocks17.12下编译运行结果如下
charBit size is 1
charBit test castInt is 65
charBit test castChar is A
charBit test is 0x41
将代码中打印1号行注释掉后运行结果如下
charBit test castInt is 4200769
charBit test castChar is A
charBit test is 0x401941
两者打印结果不同
二、分析问题
1、第一轮打印
第二个打印语句使用了错误的格式化符号来输出charBit类型的test变量,因此输出的结果为test变量的ASCII码值。这里假设代码被编译在ASCII编码环境下。
charBit结构体定义中,cBitL和cBitH分别为4位的位域,共占据了1个字节(8位)的存储空间。在这里设置test变量的cBitL为0x1,cBitH为0x4
因此在ASCII码环境下,test变量的值可以表示为二进制0001 0100,即16进制的0x14,而0x14的ASCII码值为65。
因此,当直接使用错误的格式化符号"%d"时,输出的结果是65。
2、第二轮打印
在charBit结构体中,cBitL和cBitH都只占用了4个bit位,将cBitL的值设置为0x1,即二进制001,将cBitH的值设置为0x4,即二进制0100
当这两个位域合并为一个字节时,其对应的二进制值为00010100
即16进制数0x14,而0x14对应的ASCII值为’\x14’或者20
十进制数值 20 的 ASCII 码值为 0x14(16进制)
65对应的ASCII码值为 0x41(16进制)
当将这两个ASCII码值相加时,会得到十进制数值 85(0x55,16进制)
在最初的代码中,程序使用了错误的格式化标识符 “%d” 对 test 变量进行格式化输出。因此,当程序运行时,printf函数将 test 变量的内存地址视为一个指向int类型的指针,并将其解释为一个整数类型的值进行输出。由于在不同编译器和平台情况下,整型数值的字节顺序可能不同,因此具体输出结果会有所不同。在这个特定的情况下,变量 test 的二进制值为 00010100(16进制 0x14),而将其解释为一个无符号整数类型时,这个二进制值被视为所表示的十进制数值 335544320 (16进制 0x14000000)。
进一步地,当将上述的十进制数值 85(0x55,16进制)与 335544320 相加时,会得到无符号整数值 4200769。这个值是中间过程中格式化输出错误、再将test变量的内存视为int类型指针进行无意义转换的结果
在VS下时,则不会出现这种情况