题目也许大家都见过。也是一道经典的C面试题。
题目如下
typedef struct bitstruct{
int b1:5;
int :2;
int b2:2;
}bitstruct;
void main(){
bitstruct b;
memcpy(&b,"EMC EXAMINATION",sizeof(b));
printf("%d,%d\n", b.b1, b.b2);
}
答案是:5,-2.
这道题考到了“位域”,“Little Endian”和“内存补齐”(内存补齐只要知道sizeof(b)等于4就行,不是这题的重点)
首先是知识的普及:(如果都懂就跳过吧)
1.位域的概念和特点
2.Little-endian systems的内存布局特点
Big Endian
Little Endian
这里补充很重要的一点就是小尾不是以“字节”为单位的,而是以“位”。但是平时为什么我们不用考虑到“位”的层次呢?
因为小尾的机器按照小尾的存储方式存储数据后,再按小尾的方式来读取和构建数据,对于我们来说是透明的,无需转换。
比如:
0x45,即0100
正常情况下,C的内置数据类型最少读取1个字节(如char)。读取顺序是从低位开始读的。那么读取出来的值也应该是1010
0010.但是在构建这个char值时会逆转成 0100 0101.
这样读取出来的就还是 0x45 对应的字符为“E”。
但是特殊情况下,有可能不是读取一个字节。比如这题,只读取5位。那么读取出来的数应该是10100.构建int型也需要逆转,就成了00101.
好了现在来看题目:
首先,32位机一般以四字节对齐(内存补齐),sizeof(b)应该为4,从b的首地址后四个字节的内容应该为EMC和一个空格。
其次,对于这个结构来说只有第一个字节的八位和第二个字节的第一位有意义,也就是说只有E的八位二进制,和M的二进制的首位有意义。按照前面位段知识普及中提到的“(3)一个位段必须存储在同一存储单元中,不能跨两个单元;”为什么不是第一个字节的八位和第二字节的前两位呢?答案很简单,因为编译器不支持。
E的ASCII为0x45,即0100
在内存中的存储方式为:
低地址
其中b.b1对应1-5位即
其中b.b2对应8-9位即 01。取出来之后转换成int要逆序成10, 因为最高位为1所以是负数,