结构体进阶

文章详细介绍了C语言中结构体的内存对齐规则,包括成员变量的排列方式和结构体大小的计算。同时,讨论了位域的使用,包括位域的宽度限制和存储规则。最后提到了柔性数组的特点和使用优势,如内存管理的便利性和效率提升。
摘要由CSDN通过智能技术生成
结构体进阶
1.结构体内存
1.第一个成员在结构体变量偏移量为零的地址处
2.其他成员变量对齐到某个数字(对齐数)的整数倍的地址处
对齐数=编译器默认的一个对齐数与成员大小的较小值
vs中默认的对齐数是8
3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍
#include<stdio.h>
struct A
{
    char a;
    short b;
    int c;
};
struct B
{
    int c;
    short b;
    char a;
};
struct C
{
    char a;
    int c;
    short b;
};
struct D
{
    char a;
    char d;
    short b;
    int c;
};
struct E
{
    char a;
    short b;
    char d;
    int c;
};
struct F
{
    char a;
    short b;
    int c;
    char d;
    short f;
    char e;
};
int main(void)
{
   
    printf("A = %d\n", sizeof(aa));//结果:A = 8
    printf("B = %d\n", sizeof(bb));//结果:B = 8
    printf("C = %d\n", sizeof(cc));//结果:C = 12
    printf("D = %d\n", sizeof(dd));//结果:D = 8
    printf("E = %d\n", sizeof(ee));//结果:E = 12
    printf("F = %d\n", sizeof(ff));//结果:F = 16
    
    return 0;
}
#pragma pack(4) --设置默认对齐数为4
#pragma pack()--取消设置的默认对齐数
偏移量的计算
宏--size_t offsetof(结构体类型名,成员名)
2.位域
1.在结构体定义时,我们可以指定某个成员变量所占用的二进制位数(Bit),这就是位域。
#pragma pack(2)
typedef struct
{
    char t1 : 8;
    int t2 : 1;
    int t3 : 30;
} p;
int main()
{
    p s;
    printf( "%d", sizeof(s));
}
2.C语言标准规定,位域的宽度不能超过它所依附的数据类型的长度。通俗地讲,成员变量都是有类型的,这个类型限制了成员变量的最大长度, : 后面的数字不能超过这个长度。
3.位域的具体存储规则如下:
1) 当相邻成员的类型相同时,如果它们的位宽之和小于类型的 sizeof 大小,那么后面的成员紧邻前一个成员存储,直到不能容纳为止;如果它们的位宽之和大于类型的 sizeof 大小,那么后面的成员将从新的存储单元开始存储。
2) 当相邻成员的类型不同时,不同的编译器有不同的实现方案, GCC  会压缩存储,而 VC/VS 不会。
#pragma pack(2)
int main() {
    struct bs {
        unsigned m : 12;
        unsigned char ch : 4;
        unsigned p : 4;
    };
    printf( "%d\n", sizeof( struct bs));
    return 0;
}
10
#pragma pack(4)
int main() {
    struct bs {
        unsigned m : 12;
        unsigned char ch : 4;
        unsigned p : 4;
    };
    printf( "%d\n", sizeof( struct bs));
    return 0;
}
12
3) 如果成员之间穿插着非位域成员,那么不会进行压缩。
  1. struct bs {
  2. unsigned m : 12 ;
  3. unsigned ch ;
  4. unsigned p : 4 ;
  5. } ;
  6. 12
无名位域一般用来作填充或者调整成员位置。因为没有名称,无名位域不能使用。
  1. struct bs {
  2. int m : 12 ;
  3. int : 20 ; //该位域成员不能使用
  4. int n : 4 ;
  5. } ;
0宽度位域表示当前整数包已满,下个位域分配 在新整数单元。
#pragma pack(4)
int main() {
    struct bs {
        char a : 4, : 0;
        char b : 3;
        char c : 1;
       
    };
    printf( "%d\n", sizeof( struct bs));
    return 0;
}
2
柔性数组
优点:
方便内存释放;
提高内存利用率(减少内存碎片)
访问效率更高
特点:
1.结构体的柔性数组成员前面必须至少一个其他成员。
2.sizeof返回的这种结构体大小不包括柔性数组的内存。
3.包含柔性数组成员的结构体malloc()函数进行内存的动态分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的预期大小
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值