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

内存对齐的原因:

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

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

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

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

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

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

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

test   空结构体

typedef struct node
{
     
}S;

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

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

1.test0

typedef struct node0
{
    short a;
    char b;
    short c;
}S0;

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

|--------short--------|   2字节

|--------char---------|   2字节

|--------short--------|   2字节

1.test1

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

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

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

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

总共占8字节

2.test2

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

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

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

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

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

总共占12个字节

3.test3  含有静态数据成员

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

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

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

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

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

4.test4  结构体中含有结构体

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字节

5.test5

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字节

6.test6

若在程序中使用了#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运算符  2017.10.25*/

#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;
}

C/C++ 结构体字节对齐的更多相关文章

  1. C++结构体字节对齐

    转自:http://www.cnblogs.com/JensenCat/p/4770171.html 这里是头文件结构的定义: 一个非字节对齐结构体_tagTest2 一个字节对齐_tagTest3 ...

  2. [置顶] 什么是C语言结构体字节对齐,为什么要对齐?

    一.概念 对齐跟数据在内存中的位置有关.如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐.比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的.   ...

  3. C/C++结构体字节对齐详解

    结构体的sizeof先看一个结构体:struct S1{    char c;    int i;}; sizeof(S1)在VC6中按默认设置得到的结果为8.我们先看看sizeof的定义——size ...

  4. C语言 结构体字节对齐问题

    摘选自这位大神的博客 方法一: 结构体在内存中分配一块连续的内存,但结构体内的变量并不一定是连续存放的,这涉及到内存对齐. 原则1  数据成员对齐规则:结构(struct或联合union)的数据成员, ...

  5. 【c++】【转】结构体字节对齐

    http://www.cnblogs.com/heyonggang/archive/2012/12/11/2812304.html

  6. C语言结构体的对齐原则

    Q:关于结构体的对齐,到底遵循什么原则?A:首先先不讨论结构体按多少字节对齐,先看看只以1字节对齐的情况: #include <stdio.h> #include <string.h ...

  7. C语言 结构体(联合体)对齐规则

    /* 结构体(联合体)对齐规则 */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* * ...

  8. c中结构体边界对齐

    原则1.普通数据成员对齐规则:第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储). 原则2 ...

  9. 再谈:自定义结构体的对齐问题之__attribute__ ((packed))方法【转】

    转自:https://blog.csdn.net/ipromiseu/article/details/5955295 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.c ...

随机推荐

  1. Topcoder 10748 - StringDecryption(dp)

    题面传送门 神仙题. 首先这个两次加密略微有点棘手,咱们不妨先从一次加密的情况入手考虑这个问题.显然,一次加密等价于将加密过的序列划分成若干段,每一段都是 \(xd\) 的形式表示这一段中有 \(x\ ...

  2. 洛谷 P3643 - [APIO2016]划艇(dp)

    题面传送门 一道难度中等的 \(dp\)(虽然我没有想出来/kk). 首先一眼 \(dp_{i,j}\) 表示考虑到第 \(i\) 个学校,第 \(i\) 个学校派出了 \(j\) 个划艇的方案数,转 ...

  3. Codeforces 1519F - Chests and Keys(暴搜+以网络流为状态的 dp)

    Codeforces 题目传送门 & 洛谷题目传送门 难度终于出来了--又独立切掉一道 *3200,凯信(所以我已经独立切掉三道 *3200 了?) 首先考虑我们已经知道了每个宝箱上有哪些锁, ...

  4. 【Workflows】 WGS/WES Mapping to Variant Calls

    WGS/WES Mapping to Variant Calls - Version 1.0 htslib官网上给的一个WGS/WES的流程.关于htslib.samtools和bcftools之间的 ...

  5. matplotlib 画饼图

    有个瑕疵,某一块儿比例过小时,文字会重叠. 1 def pizza(data,labs,title): 2 import matplotlib 3 import matplotlib.pyplot a ...

  6. typedef 的用法

    [2]typedef (1)在C语言中,允许使用关键字typedef定义新的数据类型 其语法如下: typedef <已有数据类型> <新数据类型>; 如: typedef i ...

  7. 漏洞分析:CVE-2017-17215

    漏洞分析:CVE-2017-17215 华为HG532路由器的命令注入漏洞,存在于UPnP模块中. 漏洞分析 什么是UPnP? 搭建好环境(使用IoT-vulhub的docker环境),启动环境,查看 ...

  8. 巩固javaweb的第三十一天

    巩固内容 变量的作用范围 如果要访问的信息在 pageScope.requestScope.sessionScope 和 applicationScope 中存储, 则使用表达式语言访问的时候可以直接 ...

  9. linux 实用指令文件目录类

    目录 linux实用指令文件目录类 路径 pwd指令 cd指令 操作文件夹/文件 ls指令 mkdir rmdir touch cp(重要) rm mv 操作内容 cat more less > ...

  10. python生成器浅析

    A 'generator' is a function which returns a generator iterator. It looks like a normal function exce ...