结构体字节对齐

2023-05-16

 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐。

      内存对齐的原因:

      1)某些平台只能在特定的地址处访问特定类型的数据;

      2)提高存取数据的速度。比如有的平台每次都是从偶地址处读取数据,对于一个int型的变量,若从偶地址单元处存放,则只需一个读取周期即可读取该变量;但是若从奇地址单元处存放,则需要2个读取周期读取该变量。

       win32平台下的微软C编译器对齐策略:

      1)结构体变量的首地址能够被其最宽数据类型成员的大小整除。编译器在为结构体变量开辟空间时,首先找到结构体中最宽的数据类型,然后寻找内存地址能被该数据类型大小整除的位置,这个位置作为结构体变量的首地址。而将最宽数据类型的大小作为对齐标准。

      2)结构体每个成员相对结构体首地址的偏移量(offset)都是每个成员本身大小的整数倍,如有需要会在成员之间填充字节。编译器在为结构体成员开辟空 间时,首先检查预开辟空间的地址相对于结构体首地址的偏移量是否为该成员大小的整数倍,若是,则存放该成员;若不是,则填充若干字节,以达到整数倍的要 求。

      3)结构体变量所占空间的大小必定是最宽数据类型大小的整数倍。如有需要会在最后一个成员末尾填充若干字节使得所占空间大小是最宽数据类型大小的整数倍。

 

下面看一下sizeof在计算结构体大小的时候具体是怎样计算的

1.test1   空结构体

?
typedef struct node
{
     
}S;

则sizeof(S)=1;或sizeof(S)=0;

在C++中占1字节,而在C中占0字节。

2.test2

?
typedef struct node1
{
     int a;
     char b;
     short c;
}S1;

则sizeof(S1)=8。这是因为结构体node1中最长的数据类型是int,占4个字节,因此以4字节对齐,则该结构体在内存中存放方式为

|--------int--------|   4字节

|char|----|--short-|   4字节

总共占8字节

3.test3

?
typedef struct node2
{
     char a;
     int b;
     short c;
}S2;

 则siezof(S3)=12.最长数据类型为int,占4个字节。因此以4字节对齐,其在内存空间存放方式如下:

|char|----|----|----|  4字节

|--------int--------|  4字节

|--short--|----|----|  4字节

总共占12个字节

4.test4  含有静态数据成员 

?
typedef struct node3
{
     int a;
     short b;
     static int c;
}S3;

则sizeof(S3)=8.这里结构体中包含静态数据成员,而静态数据成员的存放位置与结构体实例的存储地址无关(注意只有在C++中结构体中才能含有静态数据成员,而C中结构体中是不允许含有静态数据成员的)。其在内存中存储方式如下:

|--------int--------|   4字节

|--short-|----|----|    4字节

而变量c是单独存放在静态数据区的,因此用siezof计算其大小时没有将c所占的空间计算进来。

5.test5  结构体中含有结构体

?
typedef struct node4
{
     bool a;
     S1 s1;
     short b;
}S4;

则sizeof(S4)=16。是因为s1占8字节,而s1中最长数据类型为int,占4个字节,bool类型1个字节,short占2字节,因此以4字节对齐,则存储方式为

|-------bool--------|  4字节

|-------s1----------|  8字节

|-------short-------|  4字节

6.test6

?
typedef struct node5
{
     bool a;
     S1 s1;
     double b;
     int c;
}S5;

则sizeof(S5)=32。是因为s1占8字节,而s1中最长数据类型为int,占4字节,而double占8字节,因此以8字节对齐,则存放方式为:

|--------bool--------|    8字节

|---------s1---------|    8字节

|--------double------|    8字节

|----int----|---------|     8字节 

7.test7 

若在程序中使用了#pragma pack(n)命令强制以n字节对齐时,默认情况下n为8.

则比较n和结构体中最长数据类型所占的字节大小,取两者中小的一个作为对齐标准。

若需取消强制对齐方式,则可用命令#pragma pack()

如果在程序开头使用命令#pragma pack(4),对于下面的结构体

?
typedef struct node5
{
     bool a;
     S1 s1;
     double b;
     int c;
}S5;

则sizeof(S5)=24.因为强制以4字节对齐,而S5中最长数据类型为double,占8字节,因此以4字节对齐。在内存中存放方式为:

  |-----------a--------|   4字节

  |--------s1----------|   4字节

  |--------s1----------|   4字节

  |--------b-----------|   4字节

  |--------b-----------|   4字节

  |---------c----------|    4字节

总结一下,在计算sizeof时主要注意一下几点:

1)若为空结构体,则只占1个字节的单元

2)若结构体中所有数据类型都相同,则其所占空间为 成员数据类型长度×成员个数

若结构体中数据类型不同,则取最长数据类型成员所占的空间为对齐标准,数据成员包含另一个结构体变量t的话,则取t中最 长数据类型与其他数据成员比较,取最长的作为对齐标准,但是t存放时看做一个单位存放,只需看其他成员即可。

3)若使用了#pragma pack(n)命令强制对齐标准,则取n和结构体中最长数据类型占的字节数两者之中的小者作为对齐标准。

 

另外除了结构体中存在对齐之外,普通的变量存储也存在字节对齐的情况,即自身对齐。编译器规定:普通变量的存储首地址必须能被该变量的数据类型宽度整除。

测试程序:

?
/*测试sizeof运算符  2011.10.1*/
 
#include <iostream>
using namespace std;
//#pragma pack(4)    //设置4字节对齐
//#pragma pack()     //取消4字节对齐
 
typedef struct node
{
     
}S;
 
typedef struct node1
{
     int a;
     char b;
     short c;
}S1;
 
typedef struct node2
{
     char a;
     int b;
     short c;
}S2;
 
typedef struct node3
{
     int a;
     short b;
     static int c;
}S3;
 
typedef struct node4
{
     bool a;
     S1 s1;
     short b;
}S4;
 
typedef struct node5
{
     bool a;
     S1 s1;
     double b;
     int c;
}S5;
 
 
 
int main( int argc, char *argv[])
{
     cout<< sizeof ( char )<< " " << sizeof ( short )<< " " << sizeof ( int )<< " " << sizeof ( float )<< " " << sizeof ( double )<<endl;
     S s;
     S1 s1;
     S2 s2;
     S3 s3;
     S4 s4;
     S5 s5;
     cout<< sizeof (S3)<<endl;
     cout<< sizeof (s)<< " " << sizeof (s1)<< " " << sizeof (s2)<< " " << sizeof (s3)<< " " << sizeof (s4)<< " " << sizeof (s5)<<endl;
     return 0;
}
 

转载于:https://www.cnblogs.com/FuRongTao/archive/2012/03/23/2414223.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

结构体字节对齐 的相关文章

  • python----面向对象

    一 面向过程和面向对象优缺点 面向过程 xff1a 优点 xff1a 极大的降低了写程序的复杂度 xff0c 只需要顺着要执行的步骤 xff0c 堆叠代码即可 缺点 xff1a 一套流水线或者流程就是用来解决一个问题 xff0c 代码牵一发
  • Sublime Text Build 3176 安装图文详细教程

    1 著作权声明 1 1 本图文详细教程为 推优创意 原创教程 xff0c 推优创意 拥有著作权 xff0c 未经本人许可 xff0c 谢绝任何形式的全部或部分转载 xff01 违者必究 xff01 1 2 所有文章在 微信公众号 64 推优
  • iOS开发——纯代码界面(UITableViewController)

    创建UITableViewController xff08 表视图控制器 xff09 创建一个类TableViewController继承UITableViewController 1 AppDelegate m中代码如下 xff08 记得
  • iOS-CoreData详解与使用

    上面已经说完了SQLite和FMDB以及两者的区别 xff0c 本篇将讲述iOS中另一个存储方式 xff0c CoreData的使用 通读下来大约10分钟 xff0c 后续还会根据项目中问题 xff0c 不断更新 一 预备知识 在了解Cor
  • Verilog中变量位宽注意

    Verilog中 xff0c 变量定义方式可以为 xff1a reg 位宽 1 0 数据名 xff1b reg 位宽 1 数据名 其他变量也类似 以reg变量cnt为例 xff0c 当cnt位宽为4时 xff0c 可定义为reg 3 0 c
  • 使用PaintCode便捷地实现动画效果

    ViewController m paintCodeTestOC Created by LongMa on 2019 7 25 import 34 ViewController h 34 64 interface ViewControlle
  • 定位地图

    1 在iOSApp开发中 xff0c 尤其是O2O类型的的App往往包含着定位或地图这两项功能 xff0c 所以说定位和地图是iOS开发中一种常用的第三方 xff08 iOS自带高德地图 xff09 2 定位 xff1a 首先我们先来说说定
  • EXCEL中,将十六进制转换为十进制

    一 背景 1 在EXCEL表格中 xff0c 将十六进制转换为十进制的常用方法是 xff1a 使用HEX2DEC函数 2 在EXCEL的一个单元格中 xff0c 如果输入形如 34 12E36 34 之类的可以被成功识别为 科学计数法 的文
  • 关于Linux CentOS 7 中文字体安装过程心得

    一 CentOS 7 中查看现有字库 1 查看系统正在使用的语言 echo LANG en US UTF 8 2 查看系统当下所有语言环境 locale LANG 61 en US UTF 8 LC CTYPE 61 34 en US UT
  • 通过 edu 邮箱登录 Office 365 获得 1 TB 的 OneDrive 空间的方法

    要求 xff1a 你是在读大学生或高校 科研院所的教职员 1 在你就读或就业的高校或科研机构的官方网站上注册 edu 邮箱 2 登录 https www office com xff0c 用该邮箱登录 3 登录后即可启用 Office 教育
  • sqlserver 插入 更新 删除 语句中的 output子句

    官方文档镇楼 xff1a https docs microsoft com zh cn previous versions sql sql server 2008 ms177564 v 61 sql 100 从sqlserver 2005开
  • codeblocks常用快捷键

    codeblocks常用快捷键 CodeBlocks常用操作快捷键 编辑部分 xff1a Ctrl 43 A xff1a 全选 Ctrl 43 C xff1a 复制 Ctrl 43 X 剪切 Ctrl 43 V xff1a 粘贴 Ctrl
  • 1605 迷宫

    难度 xff1a 普及 题目类型 xff1a 深搜 提交次数 xff1a 1 涉及知识 xff1a 深搜 题目背景 迷宫 问题描述 给定一个N M方格的迷宫 xff0c 迷宫里有T处障碍 xff0c 障碍处不可通过 给定起点坐标和 终点坐标
  • Python3列表(list)比较操作教程

    一 相等比较 1 1 同顺序列表比较 顺序相同直接用 61 61 进行比较即可 list1 61 34 one 34 34 two 34 34 three 34 list2 61 34 one 34 34 two 34 34 three 3
  • 知识点 channel的使用

    package demo channel import 34 fmt 34 34 time 34 func main 无缓存chan ch 61 make chan int go func fmt Println 34 执行 34 ch l
  • 第五周课程总结&试验报告(三)

    实验三 String类的应用 实验目的 掌握类String类的使用 xff1b 学会使用JDK帮助文档 xff1b 实验内容1 已知字符串 xff1a 34 this is a test of java 34 按要求执行以下操作 xff1a
  • 花了快一天,才搞出来的一个client-go的demo

    用来直接获取所有service的annotaion里有ambassador的东东 或者 xff0c watch集群事件 package main import 34 fmt 34 34 os 34 34 time 34 34 strings
  • Python 入门 之 类成员

    Python 入门 之 类成员 1 类的私有成员 xff1a 私有 xff1a 只能自己拥有 以 开头就是私有内容 对于每一个类的成员而言都有两种形式 xff1a 公有成员 xff0c 在任何地方都能访问 私有成员 xff0c 只有在类的内
  • 微信小程序里两种比较时间的方法

    说明 xff1a end time是数组时的其中一个对象里的字段 1 使用过滤器 wxml 引用文件 lt wxs src 61 34 filter wxs 34 module 61 34 filterNum 34 gt 使用方法 lt v
  • error: this 'if' clause does not guard... [-Werror=misleading-indentation]

    解决办法就是if语句的下面加 报错的 if pMem return LOS NOK 修改后 if pMem return LOS NOK 转载于 https www cnblogs com 429512065qhq p 10607924 h

随机推荐