二、结构体(Struct)——结构体成员的顺序分析及技巧

结构体成员的顺序

当设计结构体时,合理安排成员的顺序是很重要的,可以优化内存利用率并减少填充字节的数量。

#include <stdio.h>
// 结构体 A(按照成员从大到小的顺序排列)
struct nodeA {
    double d;    // 占用 8 个字节
    double d2;   // 占用 8 个字节
    int c;       // 占用 4 个字节
    short b;     // 占用 2 个字节
    char a;      // 占用 1 个字节
};

// 结构体 B(按照成员从小到大的顺序排列)
struct nodeB {
    char a;      // 占用 1 个字节
    short b;     // 占用 2 个字节
    int c;       // 占用 4 个字节
    double d;    // 占用 8 个字节
    double d2;   // 占用 8 个字节
};

// 结构体 C(顺序打乱)
struct nodeC {
    double d2;   // 占用 8 个字节
    short b;     // 占用 2 个字节
    char a;      // 占用 1 个字节
    double d;    // 占用 8 个字节
    int c;       // 占用 4 个字节
};



int main() {
    printf("sizeof(A) = %zu\n", sizeof(struct nodeA));
    printf("sizeof(B) = %zu\n", sizeof(struct nodeB));
    printf("sizeof(C) = %zu\n", sizeof(struct nodeC));

    return 0;
}
//输出结果:

sizeof(A) = 32
sizeof(B) = 24
sizeof(C) = 32

注意:以上结果的大小可能会受到编译器的优化和对齐规则的影响。不同的编译器和编译选项可能会产生不同的结果。

分析

根据计算结果和结构体成员的排列方式,我们可以得出以下分析:

  • 结构体 A 的大小为 32 字节:

在这里插入图片描述

由于成员按照从大到小的顺序排列,结构体的内存布局可能存在空洞,导致空间浪费。这种方式在某些特定情况下可能会导致内存使用效率低下。

  • 结构体 B 的大小为 24 字节:

在这里插入图片描述

按照成员从小到大的顺序排列,结构体的内存布局较为紧凑,没有明显的空洞,能够更有效地利用内存空间。

  • 结构体 C 的大小为 32 字节:

在这里插入图片描述

成员顺序打乱,虽然和结构体 A 的大小相同,但内存布局可能存在较多的空洞,造成了一定的空间浪费。

综合分析,推荐按照结构体 B 的方式进行成员排列。这种方式能够在保持较好内存利用率的同时,也有助于提高访问成员的性能。另外,需要注意的是,不同的结构体成员排列方式可能会对结构体的访问效率产生影响,尤其是在涉及到大量结构体对象的情况下,合理的成员排列有助于提高缓存命中率,进而提高性能。因此,按照从小到大的顺序排列结构体成员是一种较好的实践。

使用#pragma指令进行对齐

在C语言中,可以使用#pragma指令来指定内存对齐方式。具体的对齐方式和语法根据不同的编译器而有所差异,一般使用#pragma指令的方式如下:

#pragma pack(n)

其中,n表示对齐的字节数。常见的对齐字节数包括1、2、4、8等。

例如,下面的示例演示了如何使用#pragma指令进行内存对齐:

#include <stdio.h>

#pragma pack(1)//以1字节对齐

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

#pragma pack(4)//以4字节对齐
struct Data1 {
    char a;
    int b;
    short c;
};
int main() {
    printf("Data结构体大小:%lu\n", sizeof(struct Data));
    printf("Data1结构体大小:%lu\n", sizeof(struct Data1));
    return 0;
}
// 结果:Data结构体大小:7
//		Data1结构体大小:12

在上述示例中,使用#pragma pack(1)指定了结构体Data的对齐方式为1字节。由于对齐方式的影响,结构体的大小为7字节(1字节的字符 + 4字节的整型 + 2字节的短整型)。

使用属性(attribute)进行对齐

某些编译器支持使用特定的属性(attribute)来指定内存对齐方式。属性是一种编译器扩展功能,不同的编译器可能有不同的语法和支持程度。

例如,GCC编译器可以使用__attribute__来指定对齐方式。下面是一个示例:

#include <stdio.h>

struct Data {
    char a;
    int b;
    short c;
} __attribute__((aligned(1)));

struct Data1 {
    char a;
    int b;
    short c;
} __attribute__((aligned(4)));

int main() {
    printf("Data结构体大小:%lu\n", sizeof(struct Data));
    printf("Data1结构体大小:%lu\n", sizeof(struct Data1));
    return 0;
}
//结果:Data结构体大小:12
//		Data1结构体大小:12

在上述示例中,使用__attribute__((aligned(1)))指定了结构体Data的对齐方式为1字节。结构体的大小为12字节,与#pragma指令以4字节的对齐的示例结果相同。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小羊客栈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值