%%
# 纲要
> 主干纲要、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