关于结构体的位域(位段)的字节数

本文深入解析位域在C/C++中的使用,包括位域的大小与对齐规则,以及位域如何存储和解释数据。通过具体实例,详细说明了位域在不同情况下的内存占用和值的读取,帮助理解位域的内部机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

一、位域的大小与对齐

  如果结构体中含有位域(bit-field),那么VC中准则是:

  1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

  2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

  3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式;
       4)一个位域必须存储在同一个字节中,不能跨两个成员变量类型。如一个成员变量所剩空间不够存放另一位域时,应从下一成员变量起存放该位域。也可以有意使某位域 从下一成员变量开始。

例如:

typedef struct data{
     int a:5;
     int b:7;
     int c:3;
}DATA1;

 sizeof(DATA1)=4

分析:

int a:5占5比特, int b:5占5比特,int c:3占3比特;

5+5=10 比特 ,小于sizeof(int),即大于4字节(32比特),

同时,

10比特+3比特=13比特,依然小于sizeof(int),即小于4字节,

所以,位域a、位域b、位域c的存储空间大小共占4字节。

所以,sizeof(DATA1)=4字节。

 

typedef struct data{
     int a:29;
     int b:29;
     int c:4;
}DATA2;
sizeof(DATA2)=12。

分析:

int a:29占29比特, int b:29占27比特,int c:4占4比特;

29+29=58 比特 ,大于sizeof(int),即大于4字节(32比特),

所以,

位域a的存储空间大小为4字节;

同时,

29+4=33比特,大于sizeof(int),即大于4字节,所以位域b、位域c的存储空间大小各占4字节。

所以,sizeof(DATA2)=4字节+4字节+4字节=12字节。

 

typedef struct data{
     int a:27;
     int b:27;
     int c:4;
}DATA3;

sizeof(DATA3)=8。
分析:

int a:27占27 bits, int b:27占27 bits,int c:4占4 bits,27+27=54 比特 ,大于sizeof(int),即大于4字节(32比特)

所以,

位域a的存储空间大小为4字节;

但是,

27+4=32比特,等于sizeof(int),即4字节,

所以,

位域b和位域c的存储空间大小为4字节

所以,sizeof(DATA3)=4字节+4字节=8字节。
 

 

 

 

二、位域存放的值

#include<iostream>
using namespace std;
 
struct TEST{
	int a:5;
	int b:7;
	int c:3;
};
 
 
void main()
{
 
	TEST mytest;
	memcpy(&mytest,"HelloWorld",sizeof(mytest));
	cout<<mytest.a<<endl;		
	cout<<mytest.b<<endl;
	cout<<mytest.c<<endl;
}

结果分析:

内存拷贝函数只拷贝了4个字符到mytest中,mytest中的三个变量加起来才15位,其它17位我们不要管。那么这15位中的值是怎么样的呢?15位还没到2个字节,所以这15位中全在He中,H的AscII码为72(01001000),e的AscII 码为112(01100101),根据小端法,我们知道他们的存储方式为:01100101 01001000,a占前5位:01000即8;

b占接下来的7位,0101010即42;c占接下来的3位,110即-2(因为这里是有符号数,高位为1,表示负数,所以是-2)。
 

 

 

#include <iostream>
#include <memory.h>
using namespace std;
struct A
{
    int a:5;
    int b:3;
};
int main(void)
{
    char str[100] = "0134324324afsadfsdlfjlsdjfl";
        struct A d;
    memcpy(&d, str, sizeof(A));
    cout << d.a << endl;
    cout << d.b << endl;
    return 0;
}

$ ./langxun.exe
-16
1

结果分析:

在默认情况下,为了方便对结构体内元素的访问和管理,当结构体内的元素长度都小于处理器的位数的时候,便以结构体里面最长的元素为对其单位,即结构体的长度一定是最长的数据元素的整数倍;如果有结构体内存长度大于处理器位数的元素,那么就以处理器的位数为对齐单元。由于是32位处理器,而且结构体中a和b元素类型均为int(也是4个字节),所以结构体的A占用内存为4个字节。

上例程序中定义了位域结构A,两个个位域为a(占用5位),b(占用3位),所以a和b总共占用了结构A一个字节(低位的一个字节)。

当程序运行到14行时,d内存分配情况:

 高位 00110100 00110011   00110001    00110000 低位
       '4'       '3'       '1'          '0'  
 其中d.a和d.b占用d低位一个字节(00110000),d.a : 10000, d.b : 001

 d.a内存中二进制表示为10000,由于d.a为有符号的整型变量,输出时要对符号位进行扩展,所以结果为-16(二进制为11111111111111111111111111110000)

 d.b内存中二进制表示为001,由于d.b为有符号的整型变量,输出时要对符号位进行扩展,所以结果为1(二进制为00000000000000000000000000000001)

 

 

参考链接:

https://blog.youkuaiyun.com/mydreamremindme/article/details/10285533

https://www.cnblogs.com/bigrabbit/archive/2012/09/20/2695543.html

https://www.cnblogs.com/x_wukong/p/5743369.html

### C语言中共用体、结构体存储顺序与低地址规则 #### 共用体内存布局规则 共用体(`union`)是一组共享同一段内存空间的不同类型的变量集合。在同一时刻,只有一个成员可以保存有效值。共用体的大小由其最大成员决定[^3]。 在共用体中,所有成员都从相同的内存地址开始,即共用体的第一个字节是所有成员的起点。这意味着如果访问某个成员,则该成员会覆盖其他成员的内容。 #### 结构体存储规则 结构体中的允许开发者指定每个字段据的具体比特数。的存储方式依赖于平台和编译器实现,但一般遵循以下原则: 1. **按字节对齐**:大多数情况下,会被分配到连续的字节上,并按照数据类型的最大宽度进行对齐。例如,在 `unsigned int` 类型下定义的通常会在一个 4 字节的空间内排列[^2]。 2. **填充规则**:当剩余空间不足以容纳下一个时,编译器可能跳过当前字节并进入下一字节继续放置后续。这种行为取决于具体的编译器设置以及 `-fpack-bitfields` 等选项[^4]。 3. **低优先 vs 高优先**:不同架构对于的存储方向有所不同。某些系统采用低优先的方式(最低有效于较低地址),而另一些则采取高优先策略(最高有效处于较低地址)。这主要受目标处理器的影响。 #### 示例代码解析 以下是关于如何查看具体机器上的安排的一个例子: ```c #include <stdio.h> #include <stdint.h> struct BitField { uint8_t field1 : 1; uint8_t field2 : 3; } __attribute__((packed)); int main(void){ struct BitField bf = { .field1=1, .field2=7 }; printf("Address of structure: %p\n", (void*)&bf); printf("Value stored at address: %#X\n", *((uint8_t *)&bf)); } ``` 上述程序展示了通过打印整个结构体内容来推测内部表示形式的方法。注意这里使用了 GCC 的扩展属性 `__attribute__((packed))` 来防止默认填充影响结果解释。 #### 总结 - 对于共用体而言,所有的成员共享同一个物理置,因此不存在单独讨论“低地址”的意义;只有整体对象才有明确首址的概念。 - 关于结构体内的部分,虽然理论上存在多种可能性,但实际上大部分现代桌面级 CPU 架构倾向于把最右边或者说是数值意义上的最小权值对应至更低偏移量的置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值