在用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. 实现一个简单的类似不蒜子的PV统计器

    内部的放到gitlab pages的博客,需要统计PV,不蒜子不能准确统计,原因在于gitlab的host设置了strict-origin-when-cross-origin, 导致不蒜子不能正确获取 ...

  2. 记一次VS2010和VS2015自定义颜色的过程

    首先,是遇到的问题: 一天,使用VS2010看新项目代码时候,发现选中某个变量后,其它位置高亮显示的变量颜色太淡,不利于阅读代码,如下图.所以想修改这个颜色. 后来网上找了一遍,可以这样设置:工具-- ...

  3. iptables_超解

    查询: -t选项,指定要操作的表,使用-L选项,查看-t选项对应的表的规则,-L选项的意思是,列出规则,所以,上述命令的含义为列出filter表的所有规则 显示出了3条链INPUT链.FORWARD链 ...

  4. Python基础之列表内置方法

    目录 1. 列表 1.1 序列 1.2 通用的序列操作 1.3 列表的基本操作 1.4 列表方法 1. 列表 数据结构:以某种方式(如通过编号)组合起来的元素(如数,字符乃至其他数据结构)集合. 在p ...

  5. Oracle-where exists()、not exists() 、in()、not in()用法以及效率差异

    0.exists() 用法: select * from T1 where exists(select 1 from T2 where T1.a=T2.a) 其中 "select 1 fro ...

  6. python APScheduler模块

    简介 一般来说Celery是python可以执行定时任务, 但是不支持动态添加定时任务 (Django有插件可以动态添加), 而且对于不需要Celery的项目, 就会让项目变得过重. APSchedu ...

  7. Hive(三)【DDL 数据定义】

    目录 一.DDL数据定义 1.库的DDL 1.1创建数据库 1.2查询数据库 1.3查看数据库详情 1.4切换数据库 1.5修改数据库 1.6删除数据库 2.表的DDL 2.1创建表 2.2管理表(内 ...

  8. 【XSS】再谈CSP内容安全策略

    再谈CSP内容安全策略 之前每次都是想的很浅,或者只是个理论派,事实证明就是得动手实践 参考 CSP的用法 官方文档 通过设置属性来告诉浏览器允许加载的资源数据来源.可通过Response响应头来设置 ...

  9. 容器的分类与各种测试(三)——deque

    deque是双端队列,其表象看起来是可以双端扩充,但实际上是通过内存映射管理来营造可以双端扩充的假象,如图所示 比如,用户将最左端的buff用光时,map会自动向左扩充,继续申请并映射一个新的buff ...

  10. C++中union相关

    前两天做阿里笔试遇到一个选择题题目大概是 #include <iostream> #include <stdlib.h> using namespace std; union ...