C++元素对齐探讨
探讨内容与目标
探讨C++元素的对齐方式,并以sizeof()类型返回值,测试是否理解正确。
重点留意后面的结果分析,有经验总结哦!!!
操作环境
测试环境为Windows 10,Visual Studio 2015.
一些基本知识
- 各元素类型的sizeof,以及其相应的对齐大小需要掌握。
- data alignment 数据对齐
- data padding 数据填充
- 区分3个概念:结构体对齐大小,基本元素对齐大小,预设对齐大小
结构体对齐大小,是align(A)之后得到的大小,是本次讨论重点研究的对象,也是sizeof()以及padding的最终因素。本次讨论一般设为x。
基本元素对齐大小,就是int之类的默认对齐大小,一般而言,就是基本元素的字节数。它们以一个整体出现的话,就不受#pragma pack()指令的影响。如果,基本元素在结构体内的话,受#pragma pack()影响。本次讨论,谈及基本元素对齐大小都是指的前者。本次讨论一般设为y。
预设对齐大小,就是#pragma pack()指令的预设值,一般为1,2,4,8,16。本次讨论一般设为z。
本次研究的主题,其实质就是x = f(y1, ... ,yn, z)
的函数关系。
- 一些函数介绍
- align() //计算元素类型对齐大小
align()用于计算某个元素类型的对齐大小x,注意不是元素。
比如:
struct A
{
char a;
int b;
short c;
};
cout << alignof(A) << endl; //ok 4
A a;
cout<<alignof(a)<<endl; //error
#pragma pack()
//设置预设对齐大小
#pragma pack()
是编译器的预处理命令
可用的预设对齐大小是1、2、4、8(默认)、16;
相应的设置方法- 项目->属性->配置属性->c/c++->代码生成->结构成员对齐->进行设置
- 调用
#pragma pack(n)
。eg:#pragma pack(4); //设置预设的对齐大小为4
#pragma pack() //设置预设对齐大小为默认值, 一般为8
#pragma pack(4) //设置预设对齐大小为4
- offsetof(type, var) //求type内的var的起始地址相对于type的起始地址的偏移量
struct A
{
char a;
int b;
short c;
};
//计算结构体元素a的起始地址相对于A的起始地址的偏移量
cout << offsetof(A, a) << endl; //ok 0
cout << offsetof(A, b) << endl; //ok 4
测试代码
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
struct A1
{
char c;
};
struct A2
{
char c1;
char c2;
int a;
};
struct A3
{
char c1;
int a;
char c2;
};
struct A4
{
};
struct A5
{
char c;
double d;
char c1[7];
};
//设定预设对齐大小为2
#pragma pack(2)
struct A6
{
char a;
int b;
//short c;
};
struct A7
{
char b;
};
#pragma pack(4)
struct A8
{
A6 c1;
A7 d1;
};
//恢复默认预设大小--8
#pragma pack()
struct A9
{
char c;
struct A9_inner
{
short ss;
}a9in;
double d;
};
struct A10
{
char c;
struct A10_inner
{
short ss;
double dd;
}a10in;
double d;
};
//即使声明预设对齐大小为2,int位域还是进行32位扩展,而不是16位
#pragma pack(2)
struct A11
{
short s;
char c;
int a1 : 1;
int a2 : 4;
int a3 : 7;
};
#pragma pack()
struct A12
{
short s;
char c;
long long a1 : 1;
long long a2 : 4;
long long a3 : 7;
};
//位域超过一个整体时,首次超过的那个位域字段需要考虑对齐
struct A13
{
unsigned a : 19;
unsigned b : 11;
//19+11+4 = 34 > 32 因此,c应该在下一个int里面
unsigned c : 4;
//同理,4 + 29 = 33 > 32 存在偏移
unsigned d : 29;
char index;
};
class Base
{
};
class C1
{
char c;
Base b;
};
class C2
{
char c;
Base b;
int a;
};
class C3 :public Base
{
char c;
};
class Base1
{
char c;
int a;
};
class C4 :public Base1
{
char c1;
double d;
};
class C41
{
Base1 b;
char c1;
double d;
};
class C5 :public Base1
{
char c1;
int a;
double d;
};
class C51
{
char c1;
Base1 b;
int a;
double d;
};
class Base2
{
public:
virtual ~Base2(){ }
};
class C6
{
char c;
Base2 b;
};
class C7
{
char c;
Base2 b;
int a;
};
class C8 :public Base2
{
char c;
};
class Base3
{
char c;
public:
virtual ~Base3()
{
}
};
class