C语言结构体位域简单介绍

发布时间 2023-04-28 09:45:00作者: 行走的BUG永动机


历史文章

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;
}

结果如下

本来打算打印下每个结构体成员的地址偏移的,结果

image-20230420235839679

不让打印,无法获取地址 >_<

原文连接