%% # 纲要 > 主干纲要、Hint/线索/路标 # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later %% # 位域 bit-field 位域:为**结构体或类类型**中的**非静态数据成员** 指定 **==位宽==** 后,这样的成员称之为 "**位域**"(bit-field),即**含有指定数量的二进制位**[^1]。 位域必须是**整型或者枚举类型**,**通常使用 `unsigned int`**。 ### 位域定义 **声明位域**:在成员名之后跟上 `: 常量表达式`,示例: ```cpp strcut file_data { unsigned int day: 5; // 位宽为5 unsigned int month: 4; // 位宽为4 unsigned int year: 7; // 位宽为7 }; // 与上述声明等价 strcut file_data { unsigned int day: 5, month: 4, year: 7; }; ``` ### 位域使用 > [!caution] 取值运算符 `&` 不能用于**位域**,因为任何指针都无法指向类的位域(指针寻址的最小单位是字节) > > 因此,像 `scanf` 这类函数无法直接向位域中存储数据:`scanf("%d", &rtype.re); /* WRONG */` > > ```cpp struct RType { uint8_t re: 2, rt: 2, op: 4; }; int main() { RType rtype; rtype.re = 2; // 2-bit value allowed rtype.rt = 3; // 2-bit value allowed rtype.op = 15; // 4-bit value allowed cout << static_cast<int>(rtype.re) << endl; cout << static_cast<int>(rtype.rt) << endl; cout << static_cast<int>(rtype.op) << endl; } ``` <br><br> ### 位域的内存布局 **"位域" 的存储布局取决于具体编译器实现**(如字节对齐方式和位顺序)。 > [!NOTE] > 编译器处理位域时,通常会**将==位域==逐个放入存储单元**(如字节),**位域之间没有间隙**,**直至剩下的空间不够存放下一个位域时**,可能**从下一存储单元开始存放**,或者**跨存储单元存放**(取决于实现)。 Linux 下使用 gcc 编译器时,位域通常是按 "**==声明顺序==**" **从一个字节的低位到高位**排列,即**最先声明的位域字段==占一字节内的最低位==**,**后续位域字段依次占用更高的位**。 如下图所示: ![[Excalidraw/Excalidraw-Solution/位域.excalidraw|1150]] ##### 验证示例 ```cpp title:bit_field_exam.cpp #include <cstdio> #include <cstdint> union ints8_t { struct { uint8_t rs: 2, rt: 2, op: 4; } rtype; uint8_t inst; }; union ints16_t { struct { uint8_t rs: 4, rt: 4, op: 8; } rtype; uint16_t inst; }; template<typename T> void print_binary(T n) { size_t bits = sizeof(T) * 8; printf("0b"); for (int i = bits - 1; i >= 0; i--) { printf("%d", (n >> i) & 1); } printf("\n"); } int main() { ints8_t ins8; ins8.rtype.op = 0b1010; ins8.rtype.rt = 0b01; ins8.rtype.rs = 0b11; printf("%d\n", ins8.inst); // 输出: 167 print_binary(ins8.inst); // 输出: 0b10100111 ints16_t ins16; ins16.rtype.op = 0b1010; ins16.rtype.rt = 0b01; ins16.rtype.rs = 0b11; printf("%d\n", ins16.inst); // 输出: 2579 print_binary(ins16.inst); // 输出: 0b0000101000010011 return 0; } ``` <br><br> # ♾️参考资料 # Footnotes [^1]: 《C++ Primer》P756