本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正!

字节对齐

1. 基本概念
字节对齐:计算机存储系统中以Byte为单位存储数据,不同数据类型所占的空间不同,如:整型(int)数据占4个字节,字符型(char)数据占一个字节,短整型(short)数据占两个字节,等等。计算机为了高速的读写数据,默认情况下将数据存放在某个地址的起始位置,如:整型数据(int)默认存储在地址能被4整除的起始位置,字符型数据(char)能够存放在不论什么地址位置(被1整除),短整型(short)数据存储在地址能被2整除的起始位置。这就是默认字节对齐方式。

2. 举例说明
非常显然默认对齐方式会浪费非常多空间,比如例如以下结构:
struct student
{
    char name[5];
    int num;
    short score;
}
本来仅仅用了11bytes(5+4+2)的空间,可是因为int型默认4字节对齐,存放在地址能被4整除的起始位置,即:假设name[5]从0開始存放,它占5bytes,而num则从第8(偏移量)个字节開始存放。所以sizeof(student)=16。于是中间空出几个字节闲置着。但这样便于计算机高速读写数据,是一种以空间换取时间的方式。其数据对齐例如以下图:

|char|char|char|char|
|char|----|----|----|
|--------int--------|
|--short--|----|----|

假设我们将结构体中变量的顺序改变为:
struct student
{
    int num;
    char name[5];
    short score;
}
则,num从0開始存放,而name从第4(偏移量)个字节開始存放,连续5个字节,score从第10(偏移量)開始存放,故sizeof(student)=12。其数据对齐例如以下图:

|--------int--------|
|char|char|char|char|
|char|----|--short--|

假设我们将结构体中变量的顺序再次改为为:
struct student
{
    int num;
    short score;
    char name[5];
}
则,sizeof(student)=12。其数据对齐例如以下图:

|--------int--------|
|--short--|char|char|
|char|char|char|----|

验证代码例如以下:

#include <stdio.h>

typedef struct
{
char name[5];
int num;
short score;
}student1;

typedef struct
{
int num;
char name[5];
short score;
}student2;

typedef struct
{
int num;
short score;
char name[5];
}student3;

int main()
{
student1 s1={"Tom",1001,90};
student2 s2={1002,"Mike",91};
student3 s3={1003,92,"Jack"};

printf("student1 size = %d/n",sizeof(s1));
printf("student2 size = %d/n",sizeof(s2));
printf("student3 size = %d/n",sizeof(s3));

printf("/nstudent1 address : 0x%08x/n",&s1);
printf(" name address : 0x%08x/n",s1.name);
printf(" num address : 0x%08x/n",&s1.num);
printf(" score address : 0x%08x/n",&s1.score);

printf("/nstudent2 address : 0x%08x/n",&s2);
printf(" num address : 0x%08x/n",&s2.num);
printf(" name address : 0x%08x/n",s2.name);
printf(" score address : 0x%08x/n",&s2.score);

printf("/nstudent3 address : 0x%08x/n",&s3);
printf(" num address : 0x%08x/n",&s3.num);
printf(" score address : 0x%08x/n",&s3.score);
printf(" name address : 0x%08x/n",s3.name);

return 0;
}

执行结果例如以下:

student1 size = 16
student2 size = 12
student3 size = 12

student1 address : 0x0013ff70
name address : 0x0013ff70
num address : 0x0013ff78
score address : 0x0013ff7c

student2 address : 0x0013ff64
num address : 0x0013ff64
name address : 0x0013ff68
score address : 0x0013ff6e

student3 address : 0x0013ff58
num address : 0x0013ff58
score address : 0x0013ff5c
name address : 0x0013ff5e

3. #pragma pack()命令
为了节省空间,我们能够在编码时通过#pragma pack()命令指定程序的对齐方式,括号里是对齐的字节数,若该命令括号里的内容为空,则为默认对齐方式。比如,对于上面第一个结构体,假设通过该命令手动设置对齐字节数例如以下:

#pragma pack(2) //设置2字节对齐
struct strdent
{
    char name[5]; //本身1字节对齐,比2字节对齐小,按1字节对齐
    int num;          //本身4字节对齐,比2字节对齐大,按2字节对齐
    short score;    //本身也2字节对齐,仍然按2字节对齐
}
#pragma pack() //取消设置的字节对齐方式

则,num从第6(偏移量)个字节開始存放,score从第10(偏移量)个字节開始存放,故sizeof(student)=12,其数据对齐例如以下图:
|char|char|
|char|char|
|char|-----|
|----int----|
|----int----|
|--short---|

这样改变默认的字节对齐方式能够更充分地利用存储空间,可是这会减少计算机读写数据的速度,是一种以时间换取空间的方式。

验证代码例如以下:

#include <stdio.h>

#pragma pack(2)
typedef struct
{
char name[5];
int num;
short score;
}student1;

typedef struct
{
int num;
char name[5];
short score;
}student2;

typedef struct
{
int num;
short score;
char name[5];
}student3;
#pragma pack()

int main()
{
student1 s1={"Tom",1001,90};
student2 s2={1002,"Mike",91};
student3 s3={1003,92,"Jack"};

printf("student1 size = %d/n",sizeof(s1));
printf("student2 size = %d/n",sizeof(s2));
printf("student3 size = %d/n",sizeof(s3));

printf("/nstudent1 address : 0x%08x/n",&s1);
printf(" name address : 0x%08x/n",s1.name);
printf(" num address : 0x%08x/n",&s1.num);
printf(" score address : 0x%08x/n",&s1.score);

printf("/nstudent2 address : 0x%08x/n",&s2);
printf(" num address : 0x%08x/n",&s2.num);
printf(" name address : 0x%08x/n",s2.name);
printf(" score address : 0x%08x/n",&s2.score);

printf("/nstudent3 address : 0x%08x/n",&s3);
printf(" num address : 0x%08x/n",&s3.num);
printf(" score address : 0x%08x/n",&s3.score);
printf(" name address : 0x%08x/n",s3.name);

return 0;
}

执行结果例如以下:

student1 size = 12
student2 size = 12
student3 size = 12

student1 address : 0x0013ff74
name address : 0x0013ff74
num address : 0x0013ff7a
score address : 0x0013ff7e

student2 address : 0x0013ff68
num address : 0x0013ff68
name address : 0x0013ff6c
score address : 0x0013ff72

student3 address : 0x0013ff5c
num address : 0x0013ff5c
score address : 0x0013ff60
name address : 0x0013ff62

若该为#pragma pack(1),则执行结果例如以下:

student1 size = 11
student2 size = 11
student3 size = 11

student1 address : 0x0013ff74
name address : 0x0013ff74
num address : 0x0013ff79
score address : 0x0013ff7d

student2 address : 0x0013ff68
num address : 0x0013ff68
name address : 0x0013ff6c
score address : 0x0013ff71

student3 address : 0x0013ff5c
num address : 0x0013ff5c
score address : 0x0013ff60
name address : 0x0013ff62

4. 样例

程序例如以下:

#include <stdio.h>

class A1
{
public:
int a;
static int b;

A1();
~A1();
};

class A2
{
public:
int a;
char c;

A2();
~A2();
};

class A3
{
public:
float a;
char c;

A3();
~A3();
};

class A4
{
public:
float a;
int b;
char c;

A4();
~A4();
};

class A5
{
public:
double d;
float a;
int b;
char c;

A5();
~A5();
};

main()
{
printf("A1 size = %d/n",sizeof(A1));
printf("A2 size = %d/n",sizeof(A2));
printf("A3 size = %d/n",sizeof(A3));
printf("A4 size = %d/n",sizeof(A4));
printf("A5 size = %d/n",sizeof(A5));
}

该样例採取默认对齐方式,执行结果例如以下:

A1 size = 4
A2 size = 8
A3 size = 8
A4 size = 12
A5 size = 24

说明:静态变量存放在全局数据区内,而sizeof计算栈中分配的空间的大小,故不计算在内。

若加上#pragma pack(2)命令,则执行结果例如以下:

A1 size = 4
A2 size = 6
A3 size = 6
A4 size = 10
A5 size = 18

C++中的字节对齐的更多相关文章

  1. ACE的CDR中的字节对齐问题

    大家应该都知道计算机中间都有字节对齐问题.CPU访问内存的时候,如果从特定的地址开始访问一般可以加快速度,比如在32位机器上,如果一个32位的整数被放在能被32模除等于0的地址上,只需要访问一次,而如 ...

  2. C语言中的字节对齐以及其相关处理

    首先,我们来了解下一些基本原理: 一.什么是字节对齐一个基本类型的变量在内存中占用n个字节,则该变量的起始地址必须能够被n整除,即: 存放起始地址 % n = 0,那么,就成该变量是字节对齐的;对于结 ...

  3. C++中的字节对齐分析

    struct A { int a; char b; short c; }; struct B { char a; int b; short c; }; #pragma pack(2) struct C ...

  4. C语言中的字节对齐

    下面这个篇博客讲解很好 http://blog.csdn.net/meegomeego/article/details/9393783 总的来看分三类: 1. 不加 #pragma pack(n)伪指 ...

  5. 关于sizeof与#pragma pack 以及网络上关于字节对齐的一点感想

    工作中面试中对于字节对齐基本上是必考一个知识点,而很多面试是网络上上原题.基本上背一背就可以写正确,而关于4字节对齐我相信很多人也只是一个基本地了解,对于一些题目就感觉有问题,而且很多blog后面仍然 ...

  6. c++内存中字节对齐问题详解

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

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

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

  8. stm32中字节对齐问题(__align(n),__packed用法)

    ARM下的对齐处理   from DUI0067D_ADS1_2_CompLib 3.13 type  qulifiers 有部分摘自ARM编译器文档对齐部分  对齐的使用:  1.__align(n ...

  9. stm32中使用#pragma pack(非常有用的字节对齐用法说明)

    #pragma pack(4)   //按4字节对齐,但实际上由于结构体中单个成员的最大占用字节数为2字节,因此实际还是按2字节对齐 typedef struct { char buf[3];//bu ...

随机推荐

  1. NYOJ 145 聪明的小珂

    /* 题目大意:求解和输入数的互质的数 解题思路:求解和 n 互质的最大数.从n/2開始找 关键点:GCD函数的使用 解题人:lingnichong 解题时间:2014-10-04 16:11:55 ...

  2. JBoss vs. Tomcat

    JBoss 支持Servlet.Web Server和其它J2EE Features Servlet引擎使用Tomcat的内核 SSL性能比Tomcat快4倍(据说) 支持.net.PHP.CGI 支 ...

  3. iOS-UIImageView载入网络下载的图片(异步+多线程)

    最原始的载入网络下载的图片方式: //最原始载入网络图片方法,相当堵塞主线程,界面卡顿 -(void)setImageWithURL:(NSString *)imageDownloadUrl{ UII ...

  4. bzoj5288: [Hnoi2018]游戏

    我还是太年轻了... 考场上就是直接枚举预处理当前位置左右延伸到的最远距离,好像是水了20.. 然后噶爷爷居然随机一下就AC了????mengbier #include<cstdio> # ...

  5. flask之jinji2模板介绍

    1.1.模板传参 (1)主程序   from flask import Flask,render_template app = Flask(__name__) @app.route('/') def ...

  6. 不懂技术也可以轻松开发一款APP

    这是个衣食住行都离不开手机的时代,甚至可以说,我们不用考虑其他的东西,只要拿着手机,就可以出门做自己想做的事情. 这就是手机app的强大之处,覆盖面极广,小到聊天交友,大到投资理财.每次都是app为我 ...

  7. Python多线程原理与实现

    Date: 2019-06-04 Author: Sun Python多线程原理与实战 目的: (1)了解python线程执行原理 (2)掌握多线程编程与线程同步 (3)了解线程池的使用 1 线程基本 ...

  8. BZOJ 2820: YY的GCD 莫比乌斯反演_数学推导_线性筛

    Code: #include <cstdio> #include <algorithm> #include <cstring> #include <vecto ...

  9. Airtest ——poco

    1.  Pymysql(No module named ‘cryptography’) pip install cryptography pip install paramiko 把 cryptogr ...

  10. Java 实现简单的RPC框架

    0 引言 RPC,全称为Remote Procedure Call,即远程过程调用,它是一个计算机通信协议.它允许像调用本地服务一样调用远程服务.它可以有不同的实现方式.如RMI(远程方法调用).He ...