C语言 结构体内存对齐规则(通俗易懂版)

运行之后 是8

把 char c 放后面 是12

注释char C 运行之后,还是8字节。

int a 变成 double a

加个 char C,大小变成24;

所以内存对齐的规则是,

C 语言内存对齐规则(通俗易懂版)

内存对齐是编译器 为了让 CPU 高效访问内存,自动调整结构体 / 联合体成员内存位置和占用空间 的规则,核心目的:按规则排布,让 CPU 一次就能读到数据,不用拼接

先记住 2 个核心概念:

  1. 有效对齐值min( 成员自身大小, 编译器默认对齐数 )
    • 常见默认对齐数:32 位系统默认 4 字节,64 位系统默认 8 字节
  2. 结构体总对齐规则 :总大小必须是最大有效对齐值的整数倍

一、基础对齐规则(最常用,背会这 4 条)

适用于结构体 struct、联合体 union

  1. 第一个成员 :从偏移地址 0 开始存放
  2. 后续成员 :起始偏移地址 = 自身有效对齐值的整数倍
  3. 嵌套结构体:嵌套成员的有效对齐值 = 它内部最大成员的有效对齐值
  4. 整体收尾 :结构体总大小 = 最大有效对齐值的整数倍(不够就自动补空字节)

二、数据类型自身大小(基础)

表格

类型 32 位系统 64 位系统
char 1 字节 1 字节
short 2 字节 2 字节
int 4 字节 4 字节
float 4 字节 4 字节
long 4 字节 8 字节
double 8 字节 8 字节
指针* 4 字节 8 字节

C 语言内存对齐实战代码 + 逐行详细计算过程

环境:32 位 GCC/VS 默认对齐数 = 4通用规则再重申

  1. 首成员偏移 = 0
  2. 成员偏移地址:必须是 min(成员自身字节数, 默认对齐数4) 的整数倍
  3. 嵌套结构体:对齐标准 = 其内部最大基础类型字节数
  4. 结构体总大小:必须是整个结构体里最大对齐标准的整数倍
  5. 头文件依赖:#include <stddef.h> 才能用 offsetof

例 1 基础结构体 S1

复制代码
#include <stdio.h>
#include <stddef.h>

struct S1
{
    char  c1;   // 1字节
    short s1;   // 2字节
    int   i1;   // 4字节
};

int main(void)
{
    printf("S1 大小:%zu\n", sizeof(struct S1));
    printf("c1偏移:%zu\n", offsetof(struct S1, c1));
    printf("s1偏移:%zu\n", offsetof(struct S1, s1));
    printf("i1偏移:%zu\n", offsetof(struct S1, i1));
    return 0;
}

详细计算

  1. char c1自身 1 字节,偏移从 0 开始占用:0 号地址,占 1 字节
  2. short s1自身 2 字节,有效对齐值 = 2偏移必须是 2 的倍数,当前下一个地址是 1,不满足向后填充 1 字节,偏移定为2占用:2、3 地址
  3. int i1自身 4 字节,有效对齐值 = 4下一个地址是 4,刚好是 4 倍数,偏移4占用:4、5、6、7 地址
  4. 整体补齐结构体最大对齐值 = 4当前总占用 8 字节,已是 4 整数倍,无需补位最终大小:8 字节

结果图


例 2 调换成员顺序 S2

复制代码
#include <stdio.h>
#include <stddef.h>

struct S2
{
    char  c1;
    int   i1;
    short s1;
};

int main(void)
{
    printf("S2 大小:%zu\n", sizeof(struct S2));
    printf("c1偏移:%zu\n", offsetof(struct S2, c1));
    printf("i1偏移:%zu\n", offsetof(struct S2, i1));
    printf("s1偏移:%zu\n", offsetof(struct S2, s1));
    return 0;
}

详细计算

  1. char c1:偏移 0,占 1 字节(地址 0)
  2. int i1:对齐值 4,下一个地址 1 不满足,填充 3 字节,偏移4,占 4 字节
  3. short s1:对齐值 2,下一个地址 8,满足,偏移8,占 2 字节
  4. 现有总字节:7最大对齐值 4,向上凑 4 倍数 → 补 1 字节最终大小:12 字节

结果图


例 3 含 double 八字节类型 S3

复制代码
#include <stdio.h>
#include <stddef.h>

struct S3
{
    char    c;
    int     a;
    double  d;
};

int main(void)
{
    printf("S3 大小:%zu\n", sizeof(struct S3));
    printf("c偏移:%zu\n", offsetof(struct S3, c));
    printf("a偏移:%zu\n", offsetof(struct S3, a));
    printf("d偏移:%zu\n", offsetof(struct S3, d));
    return 0;
}

详细计算

  1. char c:偏移 0,占 1 字节
  2. int a:对齐 4,填充 3 字节,偏移 4,占 4 字节
  3. double d:自身 8 字节,有效对齐 8下一个地址 8,满足 8 倍数,偏移8,占 8 字节
  4. 最大对齐值 = 8总占用:13 字节,凑 8 倍数补 3 字节最终大小:16 字节

结果图


例 4 一级嵌套结构体

复制代码
#include <stdio.h>
#include <stddef.h>

// 内层结构体
struct Inner
{
    char ch;
    int  num;
};

// 外层嵌套
struct Outer1
{
    char x;
    struct Inner in;
    double y;
};

int main(void)
{
    printf("Inner大小:%zu\n", sizeof(struct Inner));
    printf("Outer1大小:%zu\n", sizeof(struct Outer1));

    printf("x偏移:%zu\n", offsetof(struct Outer1, x));
    printf("in偏移:%zu\n", offsetof(struct Outer1, in));
    printf("y偏移:%zu\n", offsetof(struct Outer1, y));
    return 0;
}

第一步:先算内层 Inner

  1. char ch 偏移 0 占 1
  2. int num 对齐 4,偏移 4 占 4
  3. 最大对齐 4,总大小凑 4 倍数 → Inner = 8 字节Inner 对外对齐标准 = 内部最大类型 int = 4

第二步:计算外层 Outer1

  1. char x:偏移 0,占 1 字节
  2. struct Inner in:对齐标准 4下地址 1 不满足 4 倍数,填充 3 字节,偏移4,整体占 8 字节
  3. double y:对齐 8,下一个地址 16,偏移 16,占 8 字节
  4. 外层最大对齐值 = 8整体凑 8 倍数,最终 Outer1 = 24 字节

结果图


例 5 多层深度嵌套

复制代码
#include <stdio.h>
#include <stddef.h>

struct A
{
    char a1;
    short a2;
};

struct B
{
    int b1;
    struct A ba;
};

struct C
{
    char c1;
    struct B cb;
    double c2;
};

int main(void)
{
    printf("A大小:%zu\n", sizeof(struct A));
    printf("B大小:%zu\n", sizeof(struct B));
    printf("C大小:%zu\n", sizeof(struct C));

    printf("C.c1偏移:%zu\n", offsetof(struct C, c1));
    printf("C.cb偏移:%zu\n", offsetof(struct C, cb));
    printf("C.c2偏移:%zu\n", offsetof(struct C, c2));
    return 0;
}

逐层推导

  1. 算 struct Aa1 (1) → a2 对齐 2,偏移 2,总大小 4,A 对外对齐值 = 2
  2. 算 struct Bb1 (int 4) 偏移 0 占 4ba (A) 对齐 2,直接紧跟,总大小 8,B 对外对齐值 = 4
  3. 算 struct Cc1 (char) 偏移 0 占 1cb (B) 对齐 4,偏移 4 开始放,占 8c2 (double) 对齐 8,偏移 16 开始放,占 8整体最大对齐 8,补齐后得出最终大小

结果图


例 6 强制 1 字节对齐

复制代码
#include <stdio.h>
#include <stddef.h>

#pragma pack(1)   // 强制所有成员1字节对齐,无填充
struct TestPack
{
    char c;
    int  i;
    short s;
};
#pragma pack()    // 恢复系统默认对齐

int main(void)
{
    printf("1字节对齐大小:%zu\n", sizeof(struct TestPack));
    return 0;
}

计算

取消所有填充,直接顺序排布大小 = 1+4+2 = 7 字节,无任何空位填充。

结果图


做题固定流程(直接套用)

  1. 逐个确定每个成员有效对齐数
  2. 从前往后依次定偏移地址,不够就补空字节
  3. 嵌套结构体先算内层大小 + 内层最大对齐值
  4. 全部排完后,用全局最大对齐值补齐整个结构体总长度
相关推荐
吃好睡好便好3 小时前
在Matlab中绘制横直方图
开发语言·学习·算法·matlab
星寂樱易李3 小时前
iperf3 + Python-- 网络带宽、网速、网络稳定性
开发语言·网络·python
仰泳之鹅3 小时前
【C语言】自定义数据类型2——联合体与枚举
c语言·开发语言·算法
之歆4 小时前
DAY_12JavaScript DOM 完全指南(二):实战与性能篇
开发语言·前端·javascript·ecmascript
jolimark4 小时前
C语言自学攻略:小白入门三步走
c语言·编程入门·学习路线·实践项目·自学攻略
cen__y5 小时前
Linux12(Git01)
linux·运维·服务器·c语言·开发语言·git
AI人工智能+电脑小能手5 小时前
【大白话说Java面试题 第65题】【JVM篇】第25题:谈谈对 OOM 的认识
java·开发语言·jvm
社交怪人5 小时前
【算平均分】信息学奥赛一本通C语言解法(题号2071)
c语言·开发语言
郭涤生6 小时前
不同主机之间网络通信-以太网连接复习
开发语言·rk3588