博客
关于我
C语言:结构体大小及其成员分布的探究(结构体内存对齐问题)
阅读量:773 次
发布时间:2019-03-23

本文共 2108 字,大约阅读时间需要 7 分钟。

机器、数据类型、内存对齐与内存分布

86234 想了解机器、数据类型、内存对齐与内存分布相关的知识点?在这里我将为你详细解答每一个概念。


1、基础成员大小

在不同机器上,编译器处理基础类型占用内存字节不尽相同。通常的系统环境下的数据类型如下表所示:

基础类型 LP32 ILP32
char 1 1
short 2 2
int 4 4
long 4或8 8
float 4 4
double 8 8

需要注意的是,实际项目中可以直接使用操作符 sizeof 来确定数据类型的大小。


2、内存对齐的必要性

CPU 并非按字节为单位访问内存,而是按n(n > 1)个字节为整体访问。32位或64位的CPU都会以固定字节为单位进行内存访问。

核心原因:

  • 提高CPU效率:CPU通过高速缓存(cache)加速内存访问,而不是逐字节访问内存。
  • 内存对齐:保证整体访问内存时,各字节归属统一,以减少总体访问次数。
  • 示例解释:

    假设要访问一个4字节的 int 类型变量,当 int 类型数据放在奇数地址时,会占用到下一个4字节的地址区间。这样 CPU 避免了两次访问内存,提高了效率。

    内存对齐是编译器的默认行为,但在实际使用中需谨慎对齐,否则可能影响数据正确性。


    3、联合体(共用体)的大小

    联合体也是称为 共用体,其大小不是所有成员的总和,而是满足以下条件的最小值:

    • 大于等于最大成员的大小
    • 能够满足最宽基础类型成员大小的整数倍

    示例:

    union u{    int i;    char c;};

    此联合体大小为 4字节,而不是 5字节。

    另一个示例:

    union u{    int i;    char c[10];};

    最宽基础类型成员为 int(4字节),因此联合体大小为 12字节(4 × 3)。


    4、二进制数据类型大小:32位环境

    4.1 结构体成员起始地址偏移

    我们需确保结构体成员的起始地址满足以下条件:

  • 该成员传统的基础类型大小整数倍。
  • 结构体整体大小以最宽基础类型成员的大小为对齐值。
  • 示例代码:

    #include 
    union u{ char u_c1; int u_i1;};struct A{ char c1; short s1; int i1; char c2; char *pc1; union u u1;};struct B{ char c1; short s1; char c2; int i1; char *pc1; union u u1;};struct C{ char c1; char c2; short s1; int i1; char *pc1; union u u1;};int main() { struct A a; struct B b; struct C c; printf("sizeof a : %lu\n", sizeof(a)); printf("a.c1 addr: %p\n", &a.c1); // ... 其他地址输出 return 0;}

    输出结果显示,虽然 struct Astruct B 成员相同,但内存对齐导致结构体大小不同。

    4.2 以最宽基础类型成员为对齐值

    struct D{    char c1;    short s1;    double d1;    char c2;};struct E{    char ch1;    char ch2[2];    char ch3[3];};

    struct Ddouble(8字节)为对齐值,总大小为24字节;struct Ech1ch2ch3 转换为按字节对齐。


    4.3 结构体包含结构体

    struct F{    int i1;    double d1;};struct G{    char c1;    struct F f1;};

    struct F 内部以 double 为对齐值,大小为16字节。struct Gdouble 为对齐值,总大小为24字节。


    4.4 自定义内存对齐值#pragma pack

    我们可以自定义内存对齐值:

    #pragma pack(push)#pragma pack(4)struct H{    char c1;    short s1;    double d1;    char c2;};#pragma pop

    通过#pragma pack 调整对齐值,以满足特定需求。


    4.5 位域

    在C语言中,可以使用位域来定义独立的位:

    struct I{    int i1:3;    int i2:4;    int i3:5;};

    struct I 总大小为4字节,位域用于低级编程和按位操作。


    结语

    以上内容涵盖了内存对齐、数据类型大小、联合体、结构体以及自定义对齐等核心内容。理解这些知识点是掌握C语言内存管理的基础。

    转载地址:http://axnzk.baihongyu.com/

    你可能感兴趣的文章
    Mysql8在Windows上离线安装时忘记root密码
    查看>>
    MySQL8找不到my.ini配置文件以及报sql_mode=only_full_group_by解决方案
    查看>>
    mysql8的安装与卸载
    查看>>
    MySQL8,体验不一样的安装方式!
    查看>>
    MySQL: Host '127.0.0.1' is not allowed to connect to this MySQL server
    查看>>
    Mysql: 对换(替换)两条记录的同一个字段值
    查看>>
    mysql:Can‘t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock‘解决方法
    查看>>
    MYSQL:基础——3N范式的表结构设计
    查看>>
    MYSQL:基础——触发器
    查看>>
    Mysql:连接报错“closing inbound before receiving peer‘s close_notify”
    查看>>
    mysqlbinlog报错unknown variable ‘default-character-set=utf8mb4‘
    查看>>
    mysqldump 参数--lock-tables浅析
    查看>>
    mysqldump 导出中文乱码
    查看>>
    mysqldump 导出数据库中每张表的前n条
    查看>>
    mysqldump: Got error: 1044: Access denied for user ‘xx’@’xx’ to database ‘xx’ when using LOCK TABLES
    查看>>
    Mysqldump参数大全(参数来源于mysql5.5.19源码)
    查看>>
    mysqldump备份时忽略某些表
    查看>>
    mysqldump实现数据备份及灾难恢复
    查看>>
    mysqldump数据库备份无法进行操作只能查询 --single-transaction
    查看>>
    mysqldump的一些用法
    查看>>