brealid
2020-02-02 17:39:21
在 cnblogs 博客里阅读
提供一种冷门奇怪的语法:位域定义。
引入:
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
——摘自 csdn博客 sty124578 ⤴\!^{_1}
本文主要讲解了:
- 位域的使用
- 定义位域
- 位域运算特点
- 位域定义有什么用
- 搞大工程
- 处理模形如 $2^p(p\texttt{ 为整数且大于 }0)$ 的数的运算
- 位域在 OI 中的应用
- P2033 Chessboard Dance
先提供效果代码
struct test1 {
unsigned a:2;
};
struct test1 {
unsigned a:2;
};
如上,对于该结构体,在内存中是这样的(一格 = 一位):
bit|1|2|3|4|5|6|7|8|
| a | | | | | | |
struct test2 {
unsigned a:3;
int b:1;
int :2;
unsigned d:2;
};
对应在内存中的情况:
bit|1|2|3|4|5|6|7|8|
| a |b| | d |
^^^
空位不存储有用值
struct test2 {
unsigned a:3;
int b:1;
int :0;
long long d:8;
};
对应在内存中的情况:
----------------------------------------------
[Byte 1] bit|1|2|3|4|5|6|7|8|
| a |b| |
^^^^^^^
:0表示这个字节后续的位全部舍弃
----------------------------------------------
[Byte 2] bit|1|2|3|4|5|6|7|8|
| d |
----------------------------------------------
struct test3 {
short a:17; // 不合法,short 本身占 16 个位
int b:17; // 合法
};
struct
里面定义运算结果自动上溢。
以下
struct T {
unsigned a : 3;
unsigned b : 3;
unsigned c : 3;
int d : 3;
int e : 3;
int f : 3;
};
// 已知 a = 3, b = 6, 计算 c = a + b
运算过程
bit | 4 | 3 | 2 | 1 |
----+---+---+---+---+
a | | 0 | 1 | 1 |
+ b | | 1 | 1 | 0 |
= | 1 | 0 | 0 | 1 |
c | | 0 | 0 | 1 |
// 第四 bit 值上溢,最终运算结果:c = 1
// 已知 d = 3, e = 2, 计算 f = d + e
运算过程
正负位
bit | 3 | 2 | 1 |
----+---+---+---+
d | 0 | 1 | 1 |
+ e | 0 | 1 | 0 |
= f | 1 | 0 | 1 |
// 虽然运算结果没有上溢,但由于 int 的特性,这里 c 的最终结果非 5 而是 -3
搞大工程时,一般会比较注重内存的节约。
例: 如果有两个 unsigned
型的数 unsigned short
需要
不过,引用一段来自 csdn 论坛的话:
位域是只能用于结构体中,其目的是为了牺牲时间来节省空间,这在早年内存空间少时有意义,现在一般都是牺牲空间来节省时间,因此使用位域不是一个好主意。——arong1234 ⤴
\!^{_2}
比如,有一次你需要存储一个整数