问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

C语言中位域和结构体得区别是什么?

发布网友 发布时间:2022-04-24 01:50

我来回答

2个回答

热心网友 时间:2023-10-19 22:21

C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一不小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢?

开始学的时候,也被此类问题困扰很久。其实相关的文章很多,感觉说清楚的不多。结构体到底怎样对齐?

有人给对齐原则做过总结,具体在哪里看到现在已记不起来,这里引用一下前人的经验(在没有#pragma pack宏的情况下):

原则1、数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。

原则2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)

原则3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。

这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。

例1:struct {
short a1;
short a2;
short a3;
}A;

struct{
long a1;
short a2;
}B;

sizeof(A) = 6; 这个很好理解,三个short都为2。

sizeof(B) = 8; 这个比是不是比预想的大2个字节?long为4,short为2,整个为8,因为原则3。

例2:struct A{
int a;
char b;
short c;
};

struct B{
char b;
int a;
short c;
};

sizeof(A) = 8; int为4,char为1,short为2,这里用到了原则1和原则3。

sizeof(B) = 12; 是否超出预想范围?char为1,int为4,short为2,怎么会是12?还是原则1和原则3。

深究一下,为什么是这样,我们可以看看内存里的布局情况。

a b c
A的内存布局:1111, 1*, 11

b a c
B的内存布局:1***, 1111, 11**

其中星号*表示填充的字节。A中,b后面为何要补充一个字节?因为c为short,其起始位置要为2的倍数,就是原则1。c的后面没有补充,因为b和c正好占用4个字节,整个A占用空间为4的倍数,也就是最大成员int类型的倍数,所以不用补充。

B中,b是char为1,b后面补充了3个字节,因为a是int为4,根据原则1,起始位置要为4的倍数,所以b后面要补充3个字节。c后面补充两个字节,根据原则3,整个B占用空间要为4的倍数,c后面不补充,整个B的空间为10,不符,所以要补充2个字节。

再看一个结构中含有结构成员的例子:

例3:struct A{
int a;
double b;
float c;
};

struct B{
char e[2];
int f;
double g;
short h;
struct A i;
};

sizeof(A) = 24; 这个比较好理解,int为4,double为8,float为4,总长为8的倍数,补齐,所以整个A为24。

sizeof(B) = 48; 看看B的内存布局。

e f g h i
B的内存布局:11* *, 1111, 11111111, 11 * * * * * *, 1111* * * *, 11111111, 1111 * * * *

i其实就是A的内存布局。i的起始位置要为24的倍数,所以h后面要补齐。把B的内存布局弄清楚,有关结构体的对齐方式基本就算掌握了。

以上讲的都是没有#pragma pack宏的情况,如果有#pragma pack宏,对齐方式按照宏的定义来。比如上面的结构体前加#pragma pack(1),内存的布局就会完全改变。sizeof(A) = 16; sizeof(B) = 32;

有了#pragma pack(1),内存不会再遵循原则1和原则3了,按1字节对齐。没错,这不是理想中的没有内存对齐的世界吗。

a b c
A的内存布局:1111, 11111111, 1111

e f g h i
B的内存布局:11, 1111, 11111111, 11 , 1111, 11111111, 1111

那#pragma pack(2)的结果又是多少呢?#pragma pack(4)呢?留给大家自己思考吧,相信没有问题。

还有一种常见的情况,结构体中含位域字段。位域成员不能单独被取sizeof值。C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。

使用位域的主要目的是压缩存储,其大致规则为:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

还是让我们来看看例子。

例4:struct A{
char f1 : 3;
char f2 : 4;
char f3 : 5;
};

a b c
A的内存布局:111, 1111 *, 11111 * * *

位域类型为char,第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中,而f3只能从下一个字节开始。因此sizeof(A)的结果为2。

例5:struct B{
char f1 : 3;
short f2 : 4;
char f3 : 5;
};

由于相邻位域类型不同,在VC6中其sizeof为6,在Dev-C++中为2。

例6:struct C{
char f1 : 3;
char f2;
char f3 : 5;
};

非位域字段穿插在其中,不会产生压缩,在VC6和Dev-C++中得到的大小均为3。

考虑一个问题,为什么要设计内存对齐的处理方式呢?如果体系结构是不对齐的,成员将会一个挨一个存储,显然对齐更浪费了空间。那么为什么要使用对齐呢?体系结构的对齐和不对齐,是在时间和空间上的一个权衡。对齐节省了时间。假设一个体系结构的字长为w,那么它同时就假设了在这种体系结构上对宽度为w的数据的处理最频繁也是最重要的。它的设计也是从优先提高对w位数据操作的效率来考虑的。有兴趣的可以google一下,人家就可以跟你解释的,一大堆的道理。

最后顺便提一点,在设计结构体的时候,一般会尊照一个习惯,就是把占用空间小的类型排在前面,占用空间大的类型排在后面,这样可以相对节约一些对齐空间。

本篇文章来源于:开发学院 http://e.codepub.com 原文链接:http://e.codepub.com/2010/0318/21111.php

热心网友 时间:2023-10-19 22:22

有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

struct 位域结构名
{ 位域列表 };

其中位域列表的形式为: 类型说明符 位域名:位域长度

例如:
struct bs
{
int a:8;
int b:2;
int c:6;
};

热心网友 时间:2023-11-10 23:19

C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础,但一不小心就会弄错。写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的变量总长度要大,这是怎么回事呢?

开始学的时候,也被此类问题困扰很久。其实相关的文章很多,感觉说清楚的不多。结构体到底怎样对齐?

有人给对齐原则做过总结,具体在哪里看到现在已记不起来,这里引用一下前人的经验(在没有#pragma pack宏的情况下):

原则1、数据成员对齐规则:结构(struct或联合union)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。

原则2、结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)

原则3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。

这三个原则具体怎样理解呢?我们看下面几个例子,通过实例来加深理解。

例1:struct {
short a1;
short a2;
short a3;
}A;

struct{
long a1;
short a2;
}B;

sizeof(A) = 6; 这个很好理解,三个short都为2。

sizeof(B) = 8; 这个比是不是比预想的大2个字节?long为4,short为2,整个为8,因为原则3。

例2:struct A{
int a;
char b;
short c;
};

struct B{
char b;
int a;
short c;
};

sizeof(A) = 8; int为4,char为1,short为2,这里用到了原则1和原则3。

sizeof(B) = 12; 是否超出预想范围?char为1,int为4,short为2,怎么会是12?还是原则1和原则3。

深究一下,为什么是这样,我们可以看看内存里的布局情况。

a b c
A的内存布局:1111, 1*, 11

b a c
B的内存布局:1***, 1111, 11**

其中星号*表示填充的字节。A中,b后面为何要补充一个字节?因为c为short,其起始位置要为2的倍数,就是原则1。c的后面没有补充,因为b和c正好占用4个字节,整个A占用空间为4的倍数,也就是最大成员int类型的倍数,所以不用补充。

B中,b是char为1,b后面补充了3个字节,因为a是int为4,根据原则1,起始位置要为4的倍数,所以b后面要补充3个字节。c后面补充两个字节,根据原则3,整个B占用空间要为4的倍数,c后面不补充,整个B的空间为10,不符,所以要补充2个字节。

再看一个结构中含有结构成员的例子:

例3:struct A{
int a;
double b;
float c;
};

struct B{
char e[2];
int f;
double g;
short h;
struct A i;
};

sizeof(A) = 24; 这个比较好理解,int为4,double为8,float为4,总长为8的倍数,补齐,所以整个A为24。

sizeof(B) = 48; 看看B的内存布局。

e f g h i
B的内存布局:11* *, 1111, 11111111, 11 * * * * * *, 1111* * * *, 11111111, 1111 * * * *

i其实就是A的内存布局。i的起始位置要为24的倍数,所以h后面要补齐。把B的内存布局弄清楚,有关结构体的对齐方式基本就算掌握了。

以上讲的都是没有#pragma pack宏的情况,如果有#pragma pack宏,对齐方式按照宏的定义来。比如上面的结构体前加#pragma pack(1),内存的布局就会完全改变。sizeof(A) = 16; sizeof(B) = 32;

有了#pragma pack(1),内存不会再遵循原则1和原则3了,按1字节对齐。没错,这不是理想中的没有内存对齐的世界吗。

a b c
A的内存布局:1111, 11111111, 1111

e f g h i
B的内存布局:11, 1111, 11111111, 11 , 1111, 11111111, 1111

那#pragma pack(2)的结果又是多少呢?#pragma pack(4)呢?留给大家自己思考吧,相信没有问题。

还有一种常见的情况,结构体中含位域字段。位域成员不能单独被取sizeof值。C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。

使用位域的主要目的是压缩存储,其大致规则为:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

还是让我们来看看例子。

例4:struct A{
char f1 : 3;
char f2 : 4;
char f3 : 5;
};

a b c
A的内存布局:111, 1111 *, 11111 * * *

位域类型为char,第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中,而f3只能从下一个字节开始。因此sizeof(A)的结果为2。

例5:struct B{
char f1 : 3;
short f2 : 4;
char f3 : 5;
};

由于相邻位域类型不同,在VC6中其sizeof为6,在Dev-C++中为2。

例6:struct C{
char f1 : 3;
char f2;
char f3 : 5;
};

非位域字段穿插在其中,不会产生压缩,在VC6和Dev-C++中得到的大小均为3。

考虑一个问题,为什么要设计内存对齐的处理方式呢?如果体系结构是不对齐的,成员将会一个挨一个存储,显然对齐更浪费了空间。那么为什么要使用对齐呢?体系结构的对齐和不对齐,是在时间和空间上的一个权衡。对齐节省了时间。假设一个体系结构的字长为w,那么它同时就假设了在这种体系结构上对宽度为w的数据的处理最频繁也是最重要的。它的设计也是从优先提高对w位数据操作的效率来考虑的。有兴趣的可以google一下,人家就可以跟你解释的,一大堆的道理。

最后顺便提一点,在设计结构体的时候,一般会尊照一个习惯,就是把占用空间小的类型排在前面,占用空间大的类型排在后面,这样可以相对节约一些对齐空间。

本篇文章来源于:开发学院 http://e.codepub.com 原文链接:http://e.codepub.com/2010/0318/21111.php

热心网友 时间:2023-11-10 23:19

有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

struct 位域结构名
{ 位域列表 };

其中位域列表的形式为: 类型说明符 位域名:位域长度

例如:
struct bs
{
int a:8;
int b:2;
int c:6;
};
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
二楼改水管三楼要改吗-二楼改水管导致三楼反水谁负责 ...就单立把厨房的下水道改道了,现在变三楼地漏反水了,求解决_百度知 ... ...晚上到上海,走走外滩,逛逛南京路,第二天到欢乐谷。请问外 我们准备到上海欢乐谷玩,顺便游玩下上海其他地方,3天左右的时间,求旅游... 贺姓属龙男孩最吉利的名字 贺姓男孩名字2024年9月怎么取 贺姓男孩名字2022年12月怎么取 老公姓贺我姓钟怎么取名字 拔开踏板车电热加浓导线的插接头,堵塞启动加浓油道,会有什么问题 老公与其它女人搞暧昧被发现后老婆将其女电话号码放抖音平台违法嘛? c语言 关于位域的使用 关于c语言的“位域”。 C语言中“位域”与“域宽”有什么区别。 用网银转账如何修改已经存在账户信息 工商银行,转账成功后,保存的快照在哪? 工行网银转账成功截图如何保留? 中国银行网银汇款后保存的常用收款人账号怎样删除 农行网银转账记录如何删除? 工行个人网上银行中的交易快照信息可以保留多久? 网上银行转账记录怎么删除 网银转账记录怎么删除 如何删除工商银行交易快照? 取罗什么名字好 姓罗的女生取什么名字让看字面好听起来也可以 最好有古文出处 姓罗,女生,取什么名字好 罗字起名字那个名字好分数高分 姓罗取什么名字好 有没有什么比较有趣好玩的电脑软件 求好玩的电脑小软件 能给我介绍几个电脑上用的着的有意思的软件吗? 关于C语言中位域的问题 c语言 位域长度 c语言 结构体位域问题 C语言中关于位域的疑问? 绝色混血美女,芭比娃娃般的粉嫩美少女.女主角名字是? C语言中位域大小与宽度该怎么算? 粉嫩类型小女生是最受欢迎的么 关于C语言里的位域赋值问题 求大神分享【liuxiangdada】粉嫩小女生 含苞待放480P种子下载,好人一生平安 C语言结构体位域问题 美女一身粉色吊带连衣裙,粉嫩迷人还少女,你喜欢吗? c语言位域问题 的做法,清蒸小鲫鱼怎么做好吃,清蒸小鲫鱼的家常做法 “绝色混血美女的*,完美芭比娃娃般的美少女粉嫩”的女主角叫什么名字??下载地址是什么??? 结构体定义 清蒸鲫鱼有哪些简单易学的做法? 美女之家绝对粉嫩小乳牛酸酸甜甜就是我的那个女的是谁。 C语言的结构体位定义问题 做法,清蒸小鲫鱼怎么做好吃,清蒸小鲫鱼的家常做法 C语言 位域编程