c语言结构体字节对齐的实现方法

 更新时间:2021年07月27日 10:40:09   作者:cpp加油站  
在c语言的结构体里面一般会按照某种规则去进行字节对齐。本文就来介绍一下如何实现,具有一定的参考价值,感兴趣的可以了解下

1.什么是字节对齐

在c语言的结构体里面一般会按照某种规则去进行字节对齐。

我们先看一段代码:

struct st1
{
 char name;
 double age;
 char sex;
};
//32位下 sizeof(struct st1) = 16
//64位下 sizeof(struct st1) = 24
struct st2
{
 char a;
 char b;
 char c;
};
//32位和64位下, sizeof(struct st2)都是3个字节

从以上结果可以看出,结构体st1在32位下是按照4个字节来对齐的,在64位下则是按照8个字节来对齐的,结构体st2则不管32位还是64位则都是按照1个字节对齐的。
那么我们可以总结出对齐规则如下:

  • 在所有结构体成员的字节长度都没有超出操作系统基本字节单位(32位操作系统是4,64位操作系统是8)的情况下,按照结构体中字节最大的变量长度来对齐;
  • 若结构体中某个变量字节超出操作系统基本字节单位,那么就按照系统字节单位来对齐。

注意:并不是32位就直接按照4个字节对齐,64位按照8个字节对齐。

2.为什么要有字节对齐

首先普及一点小知识,cpu一次能读取多少内存要看数据总线是多少位,如果是16位,则一次只能读取2个字节,如果是32位,则可以读取4个字节,并且cpu不能跨内存区间访问。

假设有这样一个结构体如下:

struct st3
{
    char a;
    int b;
};
//那么根据我们第1节所说的规则,在32位系统下,它就应该是8个字节的。

假设地址空间是类似下面这样的:

在没有字节对齐的情况下,变量a就是占用了0x00000001这一个字节,而变量b则是占用了0x00000002~0x000000005这四个字节,那么cpu如果想从内存中读取变量b,首先要从变量b的开始地址0x00000002读到0x0000004,然后再读取一次0x00000005这个字节,相当于读一个int,cpu从内存读取了两次。

而如果进行字节对齐的话,变量a还是占用了0x00000001这一个字节,而变量b则是占用了0x00000005~0x00000008这四个字节,那么cpu要读取变量b的话,就直接一次性从0x00000005读到0x00000008,就一次全部读取出来了。

所以说,字节对齐的根本原因其实在于cpu读取内存的效率问题,对齐以后,cpu读取内存的效率会更快。但是这里有个问题,就是对齐的时候0x00000002~0x00000004这三个字节是浪费的,所以字节对齐实际上也有那么点以空间换时间的意思,具体写代码的时候怎么选择,其实是看个人的。

3.手动设置对齐

什么情况下需要手动设置对齐:

  • 设计不同CPU下的通信协议,比如两台服务器之间进行网络通信,共用一个结构体时,需要手动设置对齐规则,确保两边结构体长度一直;
  • 编写硬件驱动程序时寄存器的结构;

手动设置对齐方式有两种:

代码里添加预编译标识:

//用法如下
#pragma pack(n)//表示它后面的代码都按照n个字节对齐
struct st3
{
    char a;
    int b;
};
#pragma pack()//取消按照n个字节对齐,是对#pragma pack(n)的一个反向操作
//这里计算sizeof(st3)=5

上面这两行其实就类似于开车的时候,走到某一段路的时候,发现一个限速60公里的指示牌,过了那一段路以后,又会有解除限速60公里的指示牌。

定义结构体时:

//用法如下
struct bbb
{
   char a;
   int b;
}__attribute__((packed));//直接按照实际占用字节来对齐,其实就是相当于按照1个字节对齐了
//这里计算sizeof(st3)=5

4.结构体比较方法

可以使用内存比较函数memcpy进行结构体比较,但因为结构体对齐可能会有填充位不一致的情况,此时需要注意:

  • 设置为1个字节对齐,使它没有空位;
  • 事先对结构体进行初始化;
memcpy(char *dest, const char* src, int len); //头文件#include<string.h>

到此这篇关于c语言结构体字节对齐的实现方法的文章就介绍到这了,更多相关c语言结构体字节对齐内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Qt编译OpenCV的实现步骤

    Qt编译OpenCV的实现步骤

    本文主要介绍了Qt编译OpenCV的实现步骤,通过详细的步骤和说明,帮助开发者在Qt环境中成功集成并编译OpenCV,从而为各类计算机视觉项目提供强大的支持,感兴趣的可以了解一下
    2024-01-01
  • C++中的explicit关键字详解

    C++中的explicit关键字详解

    这篇文章主要介绍了C++中的explicit关键字详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-07-07
  • C++求解二叉树的下一个结点问题

    C++求解二叉树的下一个结点问题

    本文将通过C++求解以下问题:给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。文中示例代码讲解详细,感兴趣的可以了解一下
    2022-04-04
  • C语言进阶二叉树的基础与销毁及层序遍历详解

    C语言进阶二叉树的基础与销毁及层序遍历详解

    朋友们好,这篇播客我们继续C++的初阶学习,现在对我们对C++的二叉树基础oj与二叉树销毁和层序遍历进行练习,让我们相互学习,共同进步
    2022-06-06
  • windows系统下C++调用matlab程序的方法详解

    windows系统下C++调用matlab程序的方法详解

    这篇文章主要给大家介绍了关于在windows系统下C++调用matlab程序的方法,文中通过示例代码介绍的非常详细,对大家学习或者使用C++具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
    2017-08-08
  • C语言中typedef的用法以及#define区别详解

    C语言中typedef的用法以及#define区别详解

    这篇文章主要给大家介绍了关于C语言中typedef用法以及#define区别的相关资料,typedef 是用来定义一种类型的新别名的,它不同于宏(#define),不是简单的字符串替换。而#define只是简单的字符串替换(原地扩展),需要的朋友可以参考下
    2021-07-07
  • C++面向对象语言自制多级菜单功能实现代码

    C++面向对象语言自制多级菜单功能实现代码

    菜单类主要负责菜单的创建、修改、删除,是包含菜单结构组织和响应函数的模型,用户拥有充分的自主性,可根据需要自定义菜单显示和响应函数,这篇文章主要介绍了C++面向对象语言自制多级菜单,需要的朋友可以参考下
    2024-06-06
  • 手把手教你如何一眼分辨是C还是C++

    手把手教你如何一眼分辨是C还是C++

    在很大程度上,C++是C的超集,这意味着一个有效的C程序也是一个有效的C++程序,下面这篇文章主要给大家介绍了关于如何一眼分辨是C还是C++的相关资料,需要的朋友可以参考下
    2023-02-02
  • C++中cin的返回值问题

    C++中cin的返回值问题

    这篇文章主要介绍了C++中cin的返回值问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • C++实现学生信息管理系统(完整版)

    C++实现学生信息管理系统(完整版)

    这篇文章主要为大家详细介绍了C++实现学生信息管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06

最新评论