因为结构体有时候需要字节对齐。一般而言,struct 的 sizeof 是所有成员字节对齐后长度相加,而 union 的 sizeof 是取最大的成员长度。

在默认情况下,编译器为每一个变量或数据单元按其自然对界条件分配空间。一般地,可以通过下面的方法来改变默认的对界条件:

(1) 使用伪指令#pragma pack(n),C编译器将按照n个字节对齐。

(2) 使用伪指令#pragma pack(),取消自定义字节对齐方式。

字节对齐的细节和编译器实现相关,但一般而言,满足以下3个准则:

(1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除。

(2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节。

(3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。

需要注意的是,基本类型是指前面提到的像 char、short、int、float、double 这样的内置数据类型。如果一个结构体中包含另外一个结构体成员,那么此时最宽基本类型成员不是该结构体成员,而是取基本类型的最宽值。

1、 默认对齐方式

#include <iostream>

using namespace std;

typedef struct
{
char ch1; // 1个字节,成员的大小为1,所以不用补齐,结构体大小就是1的整数倍,为3
char ch2;
char ch3;
}A1; typedef struct
{
int num; // 5个字节,补齐为8字节
char ch;
}A2; typedef struct
{
char a; // 1字节+补齐
int b; // 8字节
long long c; // 16字节
char d; // TotalSize= 17 ,但是不是成员c的倍数,所以+7 == 24,才是8的倍数
}A3; typedef struct
{
long num; // 4字节
char * name; // 8字节
short int data; // 10字节
char ha; // 11字节+补齐,为12字节
}A4; int main(void)
{
cout << "A1: " << sizeof(A1) << endl; // A1: 3
cout << "A2: " << sizeof(A2) << endl; // A2: 8
cout << "A3: " << sizeof(A3) << endl; // A3: 24
cout << "A4: " << sizeof(A4) << endl; // A4: 12 return 0;
}

2、位域方式

#include <iostream>

using namespace std;

typedef struct
{
char ch1:1; // 1+3+3=7位,所以只占1个字节
char ch2:3;
char ch3:3;
}A1; typedef struct
{
char ch1 : 5; // 5+5+3=13位,所以只占2个字节
char ch2 : 5;
char ch3 : 3;
}A2; typedef struct
{
char ch1 : 5; // 5+5+4=14位,却占3个字节 【注意】
char ch2 : 5;
char ch3 : 4;
}A3; typedef struct
{
char ch1 : 7; // 7+7=14位,却只占2个字节 【注意】
char ch2 : 7;
}A4; typedef struct
{
char ch1 : 1; // 偏移1个字节
int a : 16; // 偏移5个字节
int b : 16; // 偏移5个字节,因为16+16<=32,未超出“int”,所以只补齐为8个字节
}A5; typedef struct
{
char ch1 : 1; // 偏移1个字节
int a : 16; // 偏移5个字节
int b : 17; // 偏移5个字节,因为16+17>33,超出“int”,所以补齐为12个字节
}A6; int main(void)
{
cout << "A1: " << sizeof(A1) << endl; // A1: 1
cout << "A2: " << sizeof(A2) << endl; // A2: 2
cout << "A3: " << sizeof(A3) << endl; // A3: 3
cout << "A4: " << sizeof(A4) << endl; // A4: 2
cout << "A5: " << sizeof(A5) << endl; // A5: 8
cout << "A6: " << sizeof(A6) << endl; // A6: 12 return 0;
}

3、使用#pragma pack(n)

#include <iostream>
using namespace std; #pragma pack(1) // 要求补齐为“1”的倍数
typedef struct
{
char ch1; // 1+0 字节,由于自定义了对齐方式,所以不再补齐
int b; // 5 字节
int a; // 9 字节
}A1; #pragma pack(2) // 要求补齐为“2”的倍数
typedef struct
{
char ch1; // 1+1 字节,由于自定义了对齐方式,补齐为"2"的倍数
int b; // 6 字节
int a; // 10 字节
}A2; #pragma pack(4) // 要求补齐为“4”的倍数
typedef struct
{
char ch1; // 1+3 字节,由于自定义了对齐方式,补齐为"4"的倍数
int b; // 8 字节
int a; // 12 字节
}A3; int main(void)
{
cout << "A1: " << sizeof(A1) << endl; // A1: 9
cout << "A2: " << sizeof(A2) << endl; // A2: 10
cout << "A3: " << sizeof(A3) << endl; // A3: 12 return 0;
}

注意当 #pragma pack 的 n 值等于或超过所有数据成员长度的时候,这个 n 值的大小将不产生任何效果。

4、结构体中有结构体成员

#include "stdafx.h"
#include <iostream> using namespace std; typedef struct
{
short i; // 2字节 char c; // 3字节,由于后一个数据为int类型,故补齐为4字节
int j; // 8字节 int k; // 12字节
}A1; /*
如果结构体中的成员又是另外一种结构体类型时应该怎么计算呢?只需把其展开即可。
但有一点需要注意,展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。
结构体stu5的成员ss.c的偏移量应该是4,而不是2。
*/
typedef struct
{
short i; // 2+2字节 (因为展开后的结构体的第一个成员的偏移量为4) struct
{
char c; // 5字节,补齐为8
int j; // 12字节
}A; int k; // 16字节 }A2; int main(void)
{
cout << "A1: " << sizeof(A1) << endl; // A1: 12
cout << "A2: " << sizeof(A2) << endl; // A2: 16 return 0;
}

C++中的结构体所占内存空间总结的更多相关文章

  1. C/C++ 结构体成员在内存中的对齐规则(转载)

    这几天在看王艳平的<windows 程序设计>,第5章讲解了MFC框架是怎么管理窗口句柄到窗口实例之间的映射,用到了两个类CPlex和CMapPtrToPtr,用于管理内存分配的类(避免因 ...

  2. C/C++ 结构体成员在内存中的对齐规则

    这几天在看王艳平的<windows 程序设计>,第5章讲解了MFC框架是怎么管理窗口句柄到窗口实例之间的映射,用到了两个类CPlex和CMapPtrToPtr,用于管理内存分配的类(避免因 ...

  3. C语言中处理结构体的原理

    汇编中有几种寻址方式,分别是直接寻址:(ds:[idata]).寄存器间接寻址(ds:[bx]).寄存器相对寻址(ds:[bx + idata].ds:[bx + si])基址变址寻址(ds:[bx ...

  4. x264中重要结构体参数解释,参数设置,函数说明 <转>

    x264中重要结构体参数解释http://www.usr.cc/thread-51995-1-3.htmlx264参数设置http://www.usr.cc/thread-51996-1-3.html ...

  5. C/C++编程笔记:C语言对齐问题【结构体、栈内存以及位域对齐】

    引言 考虑下面的结构体定义: 假设这个结构体的成员在内存中是紧凑排列的,且c1的起始地址是0,则s的地址就是1,c2的地址是3,i的地址是4. 现在,我们编写一个简单的程序: 运行后输出: 为什么会这 ...

  6. C/C++中的结构体

    结构体定义 结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构.   结构体作用 结构体和其他类型基础数据类型一样,例如int类型,char类型 只不过结构体可以做成 ...

  7. C语言中的结构体,结构体数组

    C语言中的结构体是一个小难点,下面我们详细来讲一下:至于什么是结构体,结构体为什么会产生,我就不说了,原因很简单,但是要注意到是结构体也是连续存储的,但要注意的是结构体里面类型各异,所以必然会产生内存 ...

  8. 再识C中的结构体

    在前面认识C中的结构体中我介绍了结构体的基础知识,下面通过这段代码来回顾一下: #include<stdio.h> #define LEN 20 struct Student{ //定义结 ...

  9. 关于C语言中结构体中的结构体成员导致的字节对齐问题

    关于结构体的字节对齐是什么,就不赘述,再此附上一篇文章,介绍字节对齐:http://www.linuxsong.org/2010/09/c-byte-alignment/ 这里的结构体字节对齐的数据类 ...

随机推荐

  1. 14、python异常处理

    一.什么是异常 在python中,错误触发的异常如下 二.异常的种类 在python中不同的异常可以用不同的类型去标识,一个异常标识一种错误. 1 .常用异常类 AttributeError 试图访问 ...

  2. python基础语法13 内置模块 subprocess,re模块,logging日志记录模块,防止导入模块时自动执行测试功能,包的理论

    subprocess模块: - 可以通过python代码给操作系统终端发送命令, 并且可以返回结果. sub: 子    process: 进程 import subprocess while Tru ...

  3. combineReducers(reducers)

    combineReducers(reducers) 随着应用变得越来越复杂,可以考虑将 reducer 函数 拆分成多个单独的函数,拆分后的每个函数负责独立管理 state 的一部分. combine ...

  4. HUSTOJ 有序表的最小和

    一次奇怪的AC经历...上周被这道题卡了3天... 传送门:http://oj.gdsyzx.edu.cn/problem.php?id=1475 题目描述 给出两个长度为n的有序表A和B,在A和B中 ...

  5. MongoDB shell 2 副本集方法

    rs.initiate()   rs.addArb()   rs.help()   rs.printReplicationInfo() 查看到副本集操作日志 rs.remove() 减少副本集节点 r ...

  6. Django 基础篇(二)视图与模板

    视图 在django中,视图对WEB请求进行回应 视图接收reqeust对象作为第一个参数,包含了请求的信息 视图就是一个Python函数,被定义在views.py中 #coding:utf- fro ...

  7. SpringBoot要点之使用Actuator监控

    Actuator是Springboot提供的用来对应用系统进行自省和监控的功能模块,借助于Actuator开发者可以很方便地对应用系统某些监控指标进行查看.统计等. 在pom文件中加入spring-b ...

  8. codevs 2803 爱丽丝·玛格特罗依德

    二次联通门 : codevs 2803 爱丽丝·玛格特罗依德 /* codevs 2803 爱丽丝·玛格特罗伊德 高精 + 找规律 显然, 能拆3就多拆3 不能拆就拆2 注意特判一下 */ #incl ...

  9. libvirt原理

    引用原文: https://blog.csdn.net/BtB5e6Nsu1g511Eg5XEg/article/details/80142155 libvirt是目前使用最为广泛的针对KVM虚拟机进 ...

  10. 责任链模式(chainOfResponsibility)

    参考文章:http://wiki.jikexueyuan.com/project/design-pattern-behavior/chain-four.html 定义: 使多个对象都有机会处理请求,从 ...