C语言结构体位域简单介绍
历史文章
0 前言
这几天看到一个有趣的结构体,之前没有见过,稍微了解了一下,顺便记录一下
以下例子均在32位操作系统操作
1 结构体简单介绍
在C语言中,每种类型的变量都会占用一定的字节数,以下面几种为例
char | 1B |
---|---|
int | 4B |
double | 8B |
结构体简单将就是,用户自定义的复合数据类型,一个结构体中可以包含多种数据类型,最为常见的例子,就是学生信息表
结构体的声明方式如下
struct 结构体名称{
类型 成员1;
类型 成员2;
...
};
那么问题来了,结构体可以包含多种数据类型,那一个定义好的结构体会占用多少字节
比如下面这个例子
#include <stdio.h>
struct example{
int a;
int b;
double c;
};
int main () {
printf("Size of example is %0d\n", sizeof(struct example));
return 0;
}
在main函数中用sizeof
打印一下结构体占用的字节数
先猜一下,int
占4B,double
占8B,计算下来应该是16B,来看运行结果
运行结果与预期相符
2 结构体的内存对齐
在CPU的存取的方式是以32bit(4 byte)为一次存取,也就是说,无论给定的data位宽为多少,CPU一次固定存取的位数固定为32bit
如果有数据超过32bit,CPU则会分多次存取
以下图为例,绿色的方框代表32bit
char
的长度是1byte,2个char
型变量共2 byte,没有超过32bit,所以CPU可以一次存取,因此这两个char
型变量的地址偏移是连续的
下面用代码佐证
#include <stdio.h>
struct example{
char a;
char b;
};
int main () {
struct example p1;
printf("a: %0d\n", (size_t)&p1.a);
printf("b: %0d\n", (size_t)&p1.b);
return 0;
}
仿真结果如下
可以看到,地址偏移数增加1
这里强调一下,在计算机的地址中,是以byte为单位的
接下来换个图
就像这样,如果在char
后紧接着是一个int
变量,那么此时结构体总共占用多少字节,int
的地址偏移又是多少
#include <stdio.h>
struct example{
char a;
int b;
};
int main () {
struct example p1;
printf("\tSize of example is %0d\n", sizeof(p1));
printf("\ta: %0d\n", (size_t)&p1.a);
printf("\tb: %0d\n", (size_t)&p1.b);
return 0;
}
先来猜测一下,如果不考虑内存对齐的因素,char
占1 byte,int
占4 byte,那结构体总的长度应该是5 byte
结果如下
可以看到二者的地址偏移并不是连续的,变量b的起始地址在a的下一个4 byte(地址偏移是负数)
并且,此时结构体的总长度是8 byte
3 结构体位域
下面来介绍一下结构体位域
结构体位域是用来将内存扣到极致的东西,在结构体位域中,可以自定义每个变量的位宽,并且是以bit为单位的
#include <stdio.h>
struct example{
char a : 5;
char b : 3;
};
int main () {
struct example p1;
printf("\tSize of example is %0d\n", sizeof(p1));
return 0;
}
在位域中,重新定义了a
占 5 bit ,b
占3 bit,那么整个结构体总共8bit,也就是1 byte
如果没有指定位域呢
#include <stdio.h>
struct example{
char a ;
char b ;
};
int main () {
struct example p1;
printf("\tSize of example is %0d\n", sizeof(p1));
return 0;
}
结果如下
本来打算打印下每个结构体成员的地址偏移的,结果
不让打印,无法获取地址 >_<
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现