位段

1.7k 词

阅读提示:本文使用了html相关控制语句设置单元格背景颜色,建议使用白色背景进行阅读(白天模式)

位段

C语言允许在一个结构体中以位为单位来指定其成员所占内存长度,这种以位为单位的成员称为“位段”或称“位段”(bit field)。
利用位段能够用较少的位数存储数据。。unsigned int a:1;表示a占1位Bit表示数字。
位段成员除了可以指定为unsigned int整形还可以指定为字符char

1
2
3
4
5
typedef struct{
unsigned int a:1;
unsigned int b:1;
unsigned int c:2;
}Bit;

在底层编程中,使用位段可以很方便地将一个存储单元划分成若干长度不等的连续内存。但其内存分配与内存对齐的实现方式依赖于具体的机器和系统,在不同的平台可能有不同的结果,这导致了位段在本质上是不可移植的。不同的IDE在处理位段这种数据结构的时候确实会有很大的不同。比如vs和DEV-c++。[1]

存储单元

存储单元就是一个C语言的基本变量,如intchar等;
位段必须存放在一个存储单元中,不能跨两个单元,一个单元空间不能容纳下一个位段,则该空间不用,而从下一个单元起存放该位段。’以下是常见的存储单元大小:

类型 单元大小(Byte) 最大长度(bit)
char 1 8
short 2 16
int 4 32
long 4 32
float 4 32
double 8 64

测试代码: [点击运行]

1
2
3
4
5
6
7
8
9
10
11
#include<stdio.h>
struct temp1{
char a:7;
char b:7;
char c:2;
}temp1;

int main(){
printf("%d\n",sizeof(temp1));
return 0;
}

输出结果:

output
1
3

分析:

char a:7表示a占7位,char b:7表示b占7位,char c:2表示c占2位,一共是16位,但是一个存储单元是8位,且成员不能跨单位存储,所以需要三个存储单元,因此sizeof(temp)的结果是3。

使用表格体现这个位段的内存划分:
存储单元1 存储单元2 存储单元3
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
a N b N c N

无名位段

如果位段的定义没有给出标识符名字,那么这是无名位段,无法被初始化。
无名位段用于填充(padding)内存布局。只有无名位段的比特数可以为0
这种占0比特的无名位段,用于强制让下一个位段在内存分配边界对齐。

测试代码: [点击运行]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<stdio.h>
struct temp1{
char a:1;
char b:2;
}temp1;
struct temp2{
char a:1;
char : 0;
char b:2;
}temp2;

int main(){
printf("temp1:%d\n",sizeof(temp1));
printf("temp2:%d\n",sizeof(temp2));
return 0;
}

输出结果:

output
1
2
temp1:1
temp2:2

内存划分:

Temp1:
存储单元1
0 1 2 3 4 5 6 7
a b N
Temp2:
存储单元1 存储单元2
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
a N b N

实现

通常在大端序系统(如PowerPC),安排位域从最重要字节(most-significant byte)到最不重要字节(least-significant byte),在一个字节内部从最重要位(most-significant bit)到最不重要位(least-significant bit);

而在小端序系统(如x86),安排位域从最不重要位(least-significant byte)到最重要字节(most-significant byte),在一个字节内部从最不重要位(least-significant bit)到最重要位(most-significant bit)。

共同遵从的原则是内存字节地址从低到高,内存内部的比特编号从低到高。[1]