结构体字节对齐

在用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和结构体中最长数据类型占的字节数两者之中的小者作为对齐标准。

C语言结构体变量字节对齐问题总结的更多相关文章

  1. C语言结构体的字节对齐原则

    为什么要对齐? 现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据 ...

  2. C语言结构体的字节对齐

    Test Code: #include <iostream> #include <cstring> using namespace std; struct A{ int a; ...

  3. C语言结构体变量私有化

    操作系统 : CentOS7.3.1611_x64 gcc版本 :4.8.5 问题描述 C语言结构体定义中的变量默认是公有(Public)属性,如果实现成员变量的私有(Private)化? 解决方案 ...

  4. C语言 结构体的内存对齐问题与位域

    http://blog.csdn.net/xing_hao/article/details/6678048 一.内存对齐 许多计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地 ...

  5. C语言结构体的内存对齐问题

    在C语言开发当中会遇到这样的情况: #include <stdio.h> struct test { int a; char b; }; int main(int argc, const ...

  6. 将c语言的结构体定义变成对应的golang语言的结构体定义,并将golang语言结构体变量的指针传递给c语言,cast C struct to Go struct

    https://groups.google.com/forum/#!topic/golang-nuts/JkvR4dQy9t4 https://golang.org/misc/cgo/gmp/gmp. ...

  7. C语言结构体变量内存分配与地址对齐

    地址对齐简单来说就是为了提高访问内存的速度. 数组的地址分配比较简单,由于数据类型相同,地址对齐是一件自然而然的事情. 结构体由于存在不同基本数据类型的组合,所以地址对齐存在不同情况,但总体来说有以下 ...

  8. 3.c语言结构体成员内存对齐详解

    一.关键一点 最关键的一点:结构体在内存中是一个矩形,而不是一个不规则形状 二.编程实战 #include <stdlib.h> #include <stdio.h> stru ...

  9. Linux C语言结构体-学习笔记

    Linux C语言结构体简介 前面学习了c语言的基本语法特性,本节进行更深入的学习. 预处理程序. 编译指令: 预处理, 宏定义, 建立自己的数据类型:结构体,联合体,动态数据结构 c语言表达式工具 ...

随机推荐

  1. Windows_pycharm下安装numpy

    https://blog.csdn.net/haishu_zheng/article/details/77489309 一.下载在网站https://pypi.python.org/pypi/nump ...

  2. Android Q Beta 6 终极测试版发布!

    前言 当今手机市场可谓是百花齐放,但手机系统却屈指可数,其中Android和iOS就占据了整个手机系统市场的99%,单单Android就占据了整个手机系统市场的86%,可谓是占据绝对优势.     其 ...

  3. JVM 发生内存溢出的 8 种原因、及解决办法

    阅读本文大概需要 2.3 分钟. 出处:割肉机 cnblogs.com/williamjie/p/11164572.html Java 堆空间 GC 开销超过限制 请求的数组大小超过虚拟机限制 Per ...

  4. c# word 插入图片问题

    情景描述: 在之前文本框中加标签,代码直接addPicture出现了意外.不起作用,怀疑是文档模板的问题,因为生成的PDF和word格式总时不时有差异,左右捣鼓下,更换文本框,更换图片形式,形状形式, ...

  5. 修改ARP缓存表大小

    在下发Mininet的ARP缓存表表项时,出现了如下的错误信息: SIOCSARP: No buffer space available 这是由于ARP表是缓存在内存中的,超过了系统对ARP缓存表大小 ...

  6. Docker安装及简单使用(Ubuntu)

    ### Ubuntu18下docker安装 * step 1: 安装必要的一些系统工具 sudo apt-get update sudo apt-get -y install apt-transpor ...

  7. [转帖]美团在Redis上踩过的一些坑-2.bgrewriteaof问题

    美团在Redis上踩过的一些坑-2.bgrewriteaof问题 博客分类: redis 运维 aofaof rewrite  转载请注明出处哈:http://carlosfu.iteye.com/b ...

  8. 百度前端技术学院task14源代码

    刚开始理解错误,以为是读取对象,结果后面才发现是二维数组. 另外对于数组排序,创建新的节点啊,输入到doM中啊,都不是很熟悉. <!DOCTYPE html> <html> & ...

  9. Luogu5611 Ynoi2013 D2T2/牛客挑战赛32F 最大子段和 分块、分治

    传送门 之前一直咕着的,因为一些特殊的原因把这道题更掉算了-- 有一个对值域莫队+线段树的做法,复杂度\(O(n\sqrt{n} \log n)\)然而牛客机子实在太慢了没有希望(Luogu上精细实现 ...

  10. SQLAlchemy 中的 Session、sessionmaker、scoped_session

    目录 一.关于 Session 1. Session是缓存吗? 2. Session作用: 3. Session生命周期: 4. Session什么时候创建,提交,关闭? 4. 获取一个Session ...