C++数据类型对齐、对齐规则

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)的函数关系。

  • 一些函数介绍
    1. align() //计算元素类型对齐大小

align()用于计算某个元素类型的对齐大小x,注意不是元素。
比如:

struct A
{
    char a;
    int b;
    short c;
};
cout << alignof(A) << endl;   //ok    4
A a;
cout<<alignof(a)<<endl;    //error
  1. #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
  1. 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
  • 5
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值