c++内存对齐问题
2016-04-27 14:03
369 查看
转载自:http://blog.csdn.net/l2show/article/details/7395777
在C语言和C++语言中相信很多人都有使用过sizeof(),这个帖子主要偏向于交流获取class和struct的字节数时候的问题。
我使用的是windows 7的32位OS 和 VS2010的旗舰版
先来一些正常的
[cpp] view
plain copy
struct testS
{
bool a;
char b;
short c;
int d;
};
class testC
{
private :
int a;
public:
float b;
char c;
bool d;
short e;
void get(int temp)
{
int cc;
}
};
int main()
{
cout<<"sizeof(testS):"<<sizeof(testS)<<endl;
cout<<"sizeof(testC):"<<sizeof(testC)<<endl;
getchar();
return 0;
}
这个时候相信大家都能想到输出的结果是
从这里我们可以看到我们用sizeof()取struct和class的字节的时候只有他们的成员变量才算进去的,方法及其内部的变量是不算的。当然了,一个空类是默认1字节的。
接下来我们来做一些“不正常”的
[cpp] view
plain copy
struct testS
{
char b;
short c;
int d;
bool a;
};
class testC
{
private :
int a;
public:
float b;
char c;
short e;
bool d;
void get(int temp)
{
int cc;
}
};
int main()
{
cout<<"sizeof(testS):"<<sizeof(testS)<<endl;
cout<<"sizeof(testC):"<<sizeof(testC)<<endl;
getchar();
return 0;
}
我们这次只是调换了一下成员变量的位置,然后我们再次运行一下查看结果。
很奇怪的结果,这个的运行结果不是我们正常想象的结果。这是为什么呢?
原来struct和class中为变量分配空间是以结构中最长数据元素为对齐方式的。
例如之前我们看过的例子(class 和 struct一样我们就以struct为例):
testS 一:
变量 分配空间(字节) 占用空间(字节) 起始地址
bool a 4 1 1
char b 0 1 2
short c 0 2 3
int d 4 4 5
通过这个我们可以看到分配空间是以最高的int为主的,如果可以填充的话就填充。sizeof(testS) = 8
testS 二:
变量 分配空间(字节) 占用空间(字节) 起始地址
char b 4 1 1
short c 0 2 2
int d 4 4 5
bool a 4 1 9
比之前我们只是将变量a调换到了最后,但是整个空间分配就和之前的不一样了。sizeof(testS) = 12
通过这两次的图表对比大家可以了解是什么原因导致这个结果了吧。。
内存对齐的规则:
1、 对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数,这个数据成员的自身长度) 的倍数。
2、 在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行对齐。
#pragma pack(n) 表示设置为n字节对齐。 VC6默认8字节对齐
在判断如何对齐的时候,我们可以根据偏移量和自身类型的sizeof的倍数来决定例如:
[cpp] view
plain copy
struct testS
{
char b;
int c;
double d;
};
在给char b申请内存时偏移量为0,是sizeof(char)的倍数直接分配。
在给int c申请内存时偏移量为1,不是sizeof(int)的倍数所以要填充3个字节让偏移量达到4成为sizeof(int)的倍数然后为其分配内存。
在给double d申请内存时偏移量为8时sizeof(double)的倍数,直接分配。
所以最后sizeof(testS)的结果是16
[cpp] view
plain copy
struct testS
{
int c;
char b;
};
在testS中按照上面描述的方法进行分配内存。
分配int c时偏移量为0直接分配
分配char b时偏移量为4直接分配
那么sizeof(testS)就是5了吗? 结果显然不是的··········
这只是完成了数据成员的内存对齐,还没有做结构本身的内存对齐。按照结构本身的对齐规则来说,我们要取出所有成员和#pragma pack指定的数值中较小的一个得倍数来对齐结构。所以sizeof(testS)的结果是8
[cpp] view
plain copy
<pre name="code" class="cpp">struct testS
{
char b;
int c;
double d;
public:
virtual void fun();
};</pre><br>
<p></p>
<pre></pre>
<span style="font-size:18px">还有一点需要注意的是当一个struct或者class中有虚函数或者纯虚函数的时候,因为编译器要为该类产生一个VTABLE和Vpoint来实现晚绑定,所以类中有一个隐藏的void *指针,这个时候testS所占的内存就不同了sizeof(testS)应该是24</span><br>
<p></p>
<p><span style="font-size:18px"><span style="font-size:18px"><span style="font-size:18px"><br>
</span></span></span></p>
<p><span style="font-size:18px"><span style="font-size:18px"><span style="font-size:18px"><span style="font-size:18px"><strong>#pragma pack(n) 用法</strong></span><br>
</span></span></span></p>
<p><span style="font-size:18px"><span style="font-family:宋体,Arial; line-height:21px">VC 中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;<strong style="font-size:14px"> </strong></span><br>
</span></p>
<p><span style="font-size:18px"></span></p><pre name="code" class="cpp">#pragma pack(4)
struct testS
{
char a;
double b;
int c;
}; </pre><br>
因为我们设置过了对齐的大小为4<p></p>
<p><span style="font-size:18px">在分配char a时偏移为0,直接分配</span></p>
<p><span style="font-size:18px">在分配double b时偏移为1,不是4的倍数,补齐3个字节分配内存</span></p>
<p><span style="font-size:18px">在分配int c时偏移为12,是4的倍数,直接分配</span></p>
<p><span style="font-size:18px"><span style="font-size:18px">所以sizeof(testS)的结果是16</span><br>
</span></p>
<p><span style="font-size:18px"><br>
</span></p>
<p><span style="font-size:18px"><br>
</span></p>
<br>
<p></p>
<br>
顶
1
踩
在C语言和C++语言中相信很多人都有使用过sizeof(),这个帖子主要偏向于交流获取class和struct的字节数时候的问题。
我使用的是windows 7的32位OS 和 VS2010的旗舰版
先来一些正常的
[cpp] view
plain copy
struct testS
{
bool a;
char b;
short c;
int d;
};
class testC
{
private :
int a;
public:
float b;
char c;
bool d;
short e;
void get(int temp)
{
int cc;
}
};
int main()
{
cout<<"sizeof(testS):"<<sizeof(testS)<<endl;
cout<<"sizeof(testC):"<<sizeof(testC)<<endl;
getchar();
return 0;
}
这个时候相信大家都能想到输出的结果是
从这里我们可以看到我们用sizeof()取struct和class的字节的时候只有他们的成员变量才算进去的,方法及其内部的变量是不算的。当然了,一个空类是默认1字节的。
接下来我们来做一些“不正常”的
[cpp] view
plain copy
struct testS
{
char b;
short c;
int d;
bool a;
};
class testC
{
private :
int a;
public:
float b;
char c;
short e;
bool d;
void get(int temp)
{
int cc;
}
};
int main()
{
cout<<"sizeof(testS):"<<sizeof(testS)<<endl;
cout<<"sizeof(testC):"<<sizeof(testC)<<endl;
getchar();
return 0;
}
我们这次只是调换了一下成员变量的位置,然后我们再次运行一下查看结果。
很奇怪的结果,这个的运行结果不是我们正常想象的结果。这是为什么呢?
原来struct和class中为变量分配空间是以结构中最长数据元素为对齐方式的。
例如之前我们看过的例子(class 和 struct一样我们就以struct为例):
testS 一:
变量 分配空间(字节) 占用空间(字节) 起始地址
bool a 4 1 1
char b 0 1 2
short c 0 2 3
int d 4 4 5
通过这个我们可以看到分配空间是以最高的int为主的,如果可以填充的话就填充。sizeof(testS) = 8
testS 二:
变量 分配空间(字节) 占用空间(字节) 起始地址
char b 4 1 1
short c 0 2 2
int d 4 4 5
bool a 4 1 9
比之前我们只是将变量a调换到了最后,但是整个空间分配就和之前的不一样了。sizeof(testS) = 12
通过这两次的图表对比大家可以了解是什么原因导致这个结果了吧。。
内存对齐的规则:
1、 对于结构的各个成员,第一个成员位于偏移为0的位置,以后每个数据成员的偏移量必须是min(#pragma pack()指定的数,这个数据成员的自身长度) 的倍数。
2、 在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行对齐。
#pragma pack(n) 表示设置为n字节对齐。 VC6默认8字节对齐
在判断如何对齐的时候,我们可以根据偏移量和自身类型的sizeof的倍数来决定例如:
[cpp] view
plain copy
struct testS
{
char b;
int c;
double d;
};
在给char b申请内存时偏移量为0,是sizeof(char)的倍数直接分配。
在给int c申请内存时偏移量为1,不是sizeof(int)的倍数所以要填充3个字节让偏移量达到4成为sizeof(int)的倍数然后为其分配内存。
在给double d申请内存时偏移量为8时sizeof(double)的倍数,直接分配。
所以最后sizeof(testS)的结果是16
[cpp] view
plain copy
struct testS
{
int c;
char b;
};
在testS中按照上面描述的方法进行分配内存。
分配int c时偏移量为0直接分配
分配char b时偏移量为4直接分配
那么sizeof(testS)就是5了吗? 结果显然不是的··········
这只是完成了数据成员的内存对齐,还没有做结构本身的内存对齐。按照结构本身的对齐规则来说,我们要取出所有成员和#pragma pack指定的数值中较小的一个得倍数来对齐结构。所以sizeof(testS)的结果是8
[cpp] view
plain copy
<pre name="code" class="cpp">struct testS
{
char b;
int c;
double d;
public:
virtual void fun();
};</pre><br>
<p></p>
<pre></pre>
<span style="font-size:18px">还有一点需要注意的是当一个struct或者class中有虚函数或者纯虚函数的时候,因为编译器要为该类产生一个VTABLE和Vpoint来实现晚绑定,所以类中有一个隐藏的void *指针,这个时候testS所占的内存就不同了sizeof(testS)应该是24</span><br>
<p></p>
<p><span style="font-size:18px"><span style="font-size:18px"><span style="font-size:18px"><br>
</span></span></span></p>
<p><span style="font-size:18px"><span style="font-size:18px"><span style="font-size:18px"><span style="font-size:18px"><strong>#pragma pack(n) 用法</strong></span><br>
</span></span></span></p>
<p><span style="font-size:18px"><span style="font-family:宋体,Arial; line-height:21px">VC 中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;<strong style="font-size:14px"> </strong></span><br>
</span></p>
<p><span style="font-size:18px"></span></p><pre name="code" class="cpp">#pragma pack(4)
struct testS
{
char a;
double b;
int c;
}; </pre><br>
因为我们设置过了对齐的大小为4<p></p>
<p><span style="font-size:18px">在分配char a时偏移为0,直接分配</span></p>
<p><span style="font-size:18px">在分配double b时偏移为1,不是4的倍数,补齐3个字节分配内存</span></p>
<p><span style="font-size:18px">在分配int c时偏移为12,是4的倍数,直接分配</span></p>
<p><span style="font-size:18px"><span style="font-size:18px">所以sizeof(testS)的结果是16</span><br>
</span></p>
<p><span style="font-size:18px"><br>
</span></p>
<p><span style="font-size:18px"><br>
</span></p>
<br>
<p></p>
<br>
顶
1
踩
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- C++联合体转换成C#结构的实现方法
- C++高级程序员成长之路
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- 解析C++中派生的概念以及派生类成员的访问属性