结构体对齐的规则详解及C++代码验证

 更新时间:2021年08月16日 16:42:12   投稿:BJT  
在c语言的结构体里面一般会按照某种规则去进行字节对齐。本文就来介绍一下如何实现,具有一定的参考价值,感兴趣的可以了解下

基本概念

CPU一次能读取多少个字节的数据主要是看数据总线是多少位的,16位CPU一次能读取2个字节,32位CPU一次能读取4个字节,64位CPU一次能读取8个字节。并且不能跨内存区间访问,这句话的意思可以理解为,如果CPU是32位的话,那么可以将整个内存区间每4个字节分为一块(BLOCK),每次读取一个BLOCK的数据。

那么对于下面这个结构体:

struct st {
    char c;
    int i;
};

如果不进行对齐操作,char 的地址范围0x00000000,int的地址范围为0x00000001----0x00000004,int分布在两个不同的BLOCK上,因此要读取int需要两次操作;如果进行4字节对齐,那么int的地址范围为0x00000004----0x00000007,处在一个BLOCK上,因此只需一次读取操作即可。缺点也显而易见,多占用了3个字节。这也是典型的一种空间换时间的方法吧。

结构体对齐的规则

结构体对齐需要满足以下三条规则,其中系统对齐模数在64位机器上默认为8字节,32位机器上默认为4字节。通过预处理指令#pargma pack(N)可以修改系统模数为N个字节。

1、以结构体第一个元素的地址为起始地址,亦即结构体的起始地址。由上可知,第一个元素的偏移量为0;

2、结构体元素对齐原则:结构体成员的对齐模数为类型大小与系统对齐模数的较小者;结构体成员的偏移量(填充)为对齐模数的整数倍。

3、结构体大小对齐原则:结构体的对齐模数为结构体最大元素与系统对齐模数的较小者;结构体的大小(填充)为结构体对齐模数的整数倍。

程序验证

测试环境为64位Windows ,VS2019,定义结构体st1,包含3个元素char,int,double,定义系统对齐模数为4个字节。

#include <iostream>

#pragma pack(4)

using Tsize = unsigned long long;
using namespace std;

struct st1 {
    char c;
    int i;
    double db;
    Tsize ch_offset() {
        return Tsize((Tsize)&this->c - (Tsize)this);
    }
    Tsize int_offset() {
        return Tsize((Tsize)&this->i - (Tsize)this);
    }
    Tsize double_offset() {
        return Tsize((Tsize)&this->db - (Tsize)this);
    }
};

int main() {
    cout << "st1结构体大小" << sizeof(st1) << endl;
    cout << "char 偏移量=" << st1().ch_offset() << endl;
    cout << "int偏移量=" << st1().int_offset() << endl;
    cout << "double偏移量=" << st1().double_offset() << endl;
    return 0;
}

首先我们按照对齐规则来进行分析。第一个元素为char,类型大小为1个字节,对齐模数min(1,4)=1,偏移量为0是对齐模数的整数倍,无需填充(从这里我们可以看到,第一个字节偏移量始终为0,是不需要填充的),下一个元素的偏移从1开始;第二个元素为int,类型大小4个字节,对齐模数为4个字节,不填充时偏移量为1,不是4的整数倍,因此这里需要填充3个字节,使得int的偏移量为4,且下一个元素偏移从8开始;第三个元素是double,类型大小为8个字节,对齐模数为4,偏移量从8开始,是4的整数倍,因此无需填充,占用8个字节,因此结构体的大小为16个字节。运行程序输出:

在这里插入图片描述

将系统对齐模数修改为1 【#pargma pack(1)】,这样的话,任何情况下都无需填充(不足一个字节的类型视为一个字节),结构体的大小即为结构体元素大小之和。运行程序输出:

在这里插入图片描述

将系统对齐模数修改为8 【#pargma pack(8)】,这样的话,任何情况下都无需填充(不足一个字节的类型视为一个字节),结构体的大小即为结构体元素大小之和。运行程序输出:

在这里插入图片描述

Emmm,好像和系统对齐模数为4时没什么变化。那我们将int 和 double的顺序换一下呢?

#include <iostream>

#pragma pack(8)

using Tsize = unsigned long long;
using namespace std;

struct st1 {
    char c;
    double db;
    int i;
    Tsize ch_offset() {
        return Tsize((Tsize)&this->c - (Tsize)this);
    }
    Tsize int_offset() {
        return Tsize((Tsize)&this->i - (Tsize)this);
    }
    Tsize double_offset() {
        return Tsize((Tsize)&this->db - (Tsize)this);
    }
};

int main() {
    cout << "st1结构体大小" << sizeof(st1) << endl;
    cout << "char 偏移量=" << st1().ch_offset() << endl;
    cout << "double偏移量=" << st1().double_offset() << endl;
    cout << "int偏移量=" << st1().int_offset() << endl;
    return 0;
}

在这里插入图片描述

顺序调了下,结构体就比原来大了8个字节!!!从中我们可以看出,将结构体元素从小到大排列,可以最大程度节省空间。

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注脚本之家的更多内容!

相关文章

  • Mac OS上搭建Apache+PHP+MySQL开发环境的详细教程

    Mac OS上搭建Apache+PHP+MySQL开发环境的详细教程

    这篇文章主要介绍了Mac OS上搭建Apache+PHP+MySQL开发环境的详细教程,包括常见的PHP连接MySQL失败问题的解决办法,需要的朋友可以参考下
    2016-01-01
  • C++ typeid 和虚函数详解

    C++ typeid 和虚函数详解

    这篇文章主要介绍了c++ typeid 和虚函数的使用,帮助大家更好的理解和使用c++,感兴趣的朋友可以了解下,希望能够给你带来帮助
    2021-09-09
  • C 字符串数组排序的小例子

    C 字符串数组排序的小例子

    C 字符串数组排序的小例子,需要的朋友可以参考一下
    2013-03-03
  • C语言超市管理系统设计

    C语言超市管理系统设计

    这篇文章主要为大家详细介绍了C语言超市管理系统设计,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • C语言实现循环队列基本操作

    C语言实现循环队列基本操作

    这篇文章主要为大家详细介绍了C语言实现循环队列基本操作,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-09-09
  • C++开发之PugiXML库基础用法示例详解

    C++开发之PugiXML库基础用法示例详解

    PugiXML库是一个功能强大、简单易用的C++ XML解析库,它提供了一组方便的函数来解析、创建和修改XML文档,本文介绍了如何使用PugiXML库来解析、创建和修改XML文档,以及如何处理错误和异常,感兴趣的朋友跟随小编一起看看吧
    2024-03-03
  • C语言中回调函数的含义与使用场景详解(2)

    C语言中回调函数的含义与使用场景详解(2)

    这篇文章主要为大家详细介绍了C语言中回调函数的含义与使用场景,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • C++ normal_distribution高斯正态分布函数的用法示例

    C++ normal_distribution高斯正态分布函数的用法示例

    高斯分布也称为正态分布(normal distribution),常用的成熟的生成高斯分布随机数序列的方法由Marsaglia和Bray在1964年提出,这篇文章主要给大家介绍了关于C++ normal_distribution高斯正态分布函数用法的相关资料,需要的朋友可以参考下
    2021-07-07
  • C++ 基数排序的实现实例代码

    C++ 基数排序的实现实例代码

    这篇文章主要介绍了C++ 基数排序的实现实例代码的相关资料,这里附有实例代码,帮助大家学习理解,需要的朋友可以参考下
    2016-11-11
  • C++解决输出链表中倒数k个结点的问题

    C++解决输出链表中倒数k个结点的问题

    这篇文章主要给大家介绍了关于如何利用C++解决输出链表中倒数k个结点的问题,文中通过实例代码介绍的非常详细,对大家学习或者使用C++具有一定的参考学习价值,需要的朋友可以参考下
    2021-12-12

最新评论