C/C++之内存对齐
数据对齐,是指数据所在的内存地址必须是该数据长度的整数倍。DWORD数据的内存起始地址能被4除尽,WORD数据的内存起始地址能被2除尽。X86 CPU能直接访问对齐的数据,当它试图访问一个未对齐的数据时,会在内部进行一系列的调整。这些调整对于程序员来说是透明的,但是会降低运行速度,所以编译器在编译程序时会尽量保证数据对齐。
不同的编译器内存对齐的方式不同。
一个小例子:在32位的机器上,数据是以4字节为对齐单位,这两个类的输出结果为什么不同?(VS2008)
- #include <iostream>
- using namespace std;
- class B
- {
- private:
- bool m_bTemp;
- int m_nTemp;
- bool m_bTemp2;
- };
- class C
- {
- private:
- int m_nTemp;
- bool m_bTemp;
- bool m_bTemp2;
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- cout<<sizeof(B)<<endl;
- cout<<sizeof(C)<<endl;
- system("pause");
- return 0;
- }
答案是:3*4=12,2*4=8
分析:在访问内存时,如果地址按4字节对齐,则访问的效率会高很多。
考虑到性能方面,编译器会对结构进行对齐处理,考虑下面的结构:
struct aStruct
{
char cValue;
int iValue;
};
直观地讲,这个结构的尺寸是sizeof(char)+sizeof(int)=6,但是在实际编译下, 这个结构尺寸默认是8,因为第二个域iValue会被对齐到第4个字节。
注意:字节对齐是编译时决定的,一旦决定则不会再改变,因此即使有对齐的因素存在,也不会出现一个结构在运行时尺寸发生变化的情况。
在本题中:第一种类的数据对齐是下面的情况:
bool ---- ---- ----
------- int ---------
bool ----- ---- ----
第二种类的数据对齐是下面的情况:
------- int ----------
bool bool ---------
所以类的大小分别3*4和2*4
一般在VC++中加上#pragma pack(n)设置内存对齐。
我们可以利用#pragma pack()来改变编译器的默认对齐方式。
#pragma pack(n) //编译器将按照n字节对齐
#pragma pack() //编译器将取消自定义字节对齐方式
在#pragma pack(n)和#pragma pack()之间的代码按n字节对齐。
但是成员对齐有一个重要的条件,即每个成员按照自己的对齐方式对齐;也就是说虽然指定了按n字节对齐,但并不是所有的成员都以n字节对齐。
对齐的规则是:每个成员按其类型的对齐参数(通常是这个类型的大小)和指定对齐参数(这里是n字节)中较小的一个对齐,即min(n,sizeof(item)),并且结构的长度必须为所用过的所有对齐参数的整数倍,不够就补空字节。
- #pragma pack(8)
- struct TestStruct4
- {
- char a;
- long b;
- };
- struct TestStruct5
- {
- char c;
- TestStruct4 d;
- long long e;
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- cout<<sizeof(TestStruct4)<<endl;
- cout<<sizeof(TestStruct5)<<endl;
- system("pause");
- return 0;
- }
运行结果为:8,24
分析:
TestStruct4 中,成员a是1字节,默认按照1字节对齐,指定对齐参数是8,这两个值中取1,a按1字节对齐;
成员b是4字节,默认是按4字节对齐,这时就按4字节对齐,所以sizeof(TestStruct4)应该是8.
TestStruct5 中,c和TestStruct4中的a一样,按1字节对齐;而d是个结构,它是8字节,对于结构来说,它的默认对齐方式就是其所有成员使用的对齐参数中最大的一个,TestStruct4就是4,所以成员d就按照4字节对齐。成员e是8字节,它是默认的8字节对齐,和指定的一样,所以它对齐到8自己的边界上,这时,已经使用了12字节了,所以又添加了4字节的空间,从第16字节开始放置成员e。这时长度为24,已经可以被8整除(成员e按8字节对齐)。这样一共使用了24字节。
内存布局图如下:
TestStruct4 的内存布局:
a b
1*** 1111
TestStruct5 的内存布局:
c d.a d.b e
1*** 1*** 1111 **** 11111111
注意3点:
(1)每个成员按照自己的方式对齐,并能最小化长度
(2)复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式,这样在成员是复杂类型时,可以最小化长度。
(3)对齐后的长度必须是成员中最大的对齐参数的整数倍,这样在处理数组时可以保证每一项都边界对齐。
补充:对于数组,比如说char a[3],它的对齐方式和分别写3个char是一样的,也就是说它还是按1字节对齐;如果写成typedef char Arrary3[3],Arrary3这种类型的对齐方式还是按1字节对齐,而不是按它的长度。
但是不论类型是什么,对齐的边界一定是1、2、4、8、16、32、64......中的一个。
下面来说下大端模式和小端模式
大端模式:认为第一个字节是最高位字节,也就说按照从低地址到高地址的顺序存放数据的高位字节到低位字节。
小端模式:认为第一个字节是最低位字节,也就是说按照从低地址到高地址的顺序存放数据的低位字节到高位字节。
假设从内存地址0x0000开始有以下数据:
内存地址:0x0000 0x0001 0x0002 0x0003
对应数据:0x12 0x34 0x56 0x78
如果我们去读取一个地址为0x0000的4字节变量
若字节序位为小端模式,读出为:0x78563412
若字节序位为大端模式,读出为:0x12345678
一般来说:X86系列的CPU都是小端字节序,powerPC通常是大端字节序。
- int _tmain(int argc, _TCHAR* argv[])
- {
- char *sz = "0123456789";
- int *p = (int *)sz;
- cout<<hex<<*++p<<endl;
- }
运行结果为:37363534
分析:这里是小端字节序
地址从0x0000开始,那么sz在内存中的存储为:
内存地址: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09
对应的值: 0 1 2 3 4 5 6 7 8 9
对应的值: 48 49 50 51 52 53 54 55 56 57
对应的16进制:0x30 0x31 0x32 0x33 0x34 0x35 0x36 0x37 0x38 0x39
sz ++p
所以读取为:0x37363534
C/C++之内存对齐的更多相关文章
- C++内存对齐总结
大家都知道,C++空类的内存大小为1字节,为了保证其对象拥有彼此独立的内存地址.非空类的大小与类中非静态成员变量和虚函数表的多少有关. 而值得注意的是,类中非静态成员变量的大小与编译器内存对齐的设置有 ...
- C/C++: C++位域和内存对齐问题
1. 位域: 1. 在C中,位域可以写成这样(注:位域的数据类型一律用无符号的,纪律性). struct bitmap { unsigned a : ; unsigned b : ; unsigned ...
- C/C++ 知识点1:内存对齐
预备知识:基本类型占用字节 在32位操作系统和64位操作系统上,基本数据类型分别占多少字节呢? 32位操作系统: char : 1 int :4 short : 2 unsigned ...
- Windows+GCC下内存对齐的常见问题
结构/类对齐的声明方式 gcc和windows对于modifier/attribute的支持其实是差不多的.比如在gcc的例子中,内存对齐要写成: class X { //... } __attrib ...
- c++内存对齐
内存对齐原则: 1.数据成员对齐规则:struct, union的数据成员,第一个数据成员放在offset为0的地方,之后的数据成员的存储起始位置都是放在该数据成员大小的整数倍位置.如在32bit的机 ...
- C语言中内存对齐
今天一考研同学问我一个问题,一个结构体有一个int类型成员和一个char类型成员,问我这个结构体类型占多少个字节,我直接编个程序给他看结果.这个结构体占八个字节,咦,当时我蛮纳闷的,一个int类型四个 ...
- 内存对齐 和 sizeof小结
数据对齐(内存对齐)指该数据所在的地址必须是该数据长度的整数倍.X86CPU能直接访问对齐的数据,当它试图访问未对齐的数据时,会在内部进行一系列的调整,降低运行速度.数据对齐一般出现在结构体和类中,在 ...
- 解析C语言结构体对齐(内存对齐问题)
C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的 ...
- C语言再学习之内存对齐
昨天看Q3的代码,看到有个_INTSAIZEOF的宏,着实晕了一阵.一番google后,终于明白,这个宏的作用是求出变量占用内存空间的大小,先看看_INTSAIZEOF的定义吧: #define _I ...
- C结构体中数据的内存对齐问题
转自:http://www.cnblogs.com/qwcbeyond/archive/2012/05/08/2490897.html 32位机一般默认4字节对齐(32位机机器字长4字节),64位机一 ...
随机推荐
- 号称简明实用的django上手教程
1 几个基本概念 前置条件:假设读者基本Python语言基础,或者具备某种编程语言的基础.你还熟悉web开发环境,懂些css,js,db等. Django是什么? Django是一个开放源代码的Web ...
- 计蒜客 31447 - Fantastic Graph - [有源汇上下界可行流][2018ICPC沈阳网络预赛F题]
题目链接:https://nanti.jisuanke.com/t/31447 "Oh, There is a bipartite graph.""Make it Fan ...
- POJ 3580 - SuperMemo - [伸展树splay]
题目链接:http://poj.org/problem?id=3580 Your friend, Jackson is invited to a TV show called SuperMemo in ...
- Oracle管理监控之Oracle用户权限
数据字典 1.动态数据字典是以v$xxx开始的数据字典,在数据库中约有150个左右,这些数据字典反映数据库动态运行状况,在不同时间查询会得到不同的结果. 2.DBA数据字典是以DBA_xxx表示,该数 ...
- Python:闭包
闭包(Closure) 在一个函数内部定义另一个函数,然后内部函数用到外部函数的变量,把内部函数以及用到的外部变量,合称闭包. 首先复习一下 命名空间与作用域 我们可以把命名空间看做一个大型的字典类型 ...
- Guideline 2.1 - Information Needed
For information about testing your app and preparing it for review, please see Technical Note TN2431 ...
- Area---poj1265(皮克定理+多边形求面积)
题目链接:http://poj.org/problem?id=1265 题意是:有一个机器人在矩形网格中行走,起始点是(0,0),每次移动(dx,dy)的偏移量,已知,机器人走的图形是一个多边形,求这 ...
- mysql 内置功能 触发器介绍
使用触发器可以在用户对表进行[增.删.改]操作时前后定义一些操作,注意:没有查询 创建触发器 create trigger 触发器的名字 之前(before)或者之后(after) 行为(inser ...
- Celery配置Redis数据库保存Return结果状态
使用windows版本 1.于GitHUB下载https://github.com/ServiceStack/redis-windows Window版本,到路径: 2. 运行路径下:D:\redis ...
- java-小技巧-001-Long序列化到前端js不支持
1.引入:jackson-mapper-asl-1.9.2.jar 2.导入: import org.codehaus.jackson.map.annotate.JsonSerialize;impor ...