基本数据类型,结构体,类的sizeof大小

sizeof

sizeof在C/C++作为操作符,而不是函数。sizeof操作符以字节的形式给出其操作数的大小。

字节对齐(Data structure alignment)

Wikipedia上关于字节对齐的解释:Data structure alignment is the way data is arranged and accessed in computer memory. It consists of two separate but related issues: data alignment and data structure padding. When a modern computer reads from or writes to a memory address, it will do this in word sized chunks (e.g. 4 byte chunks on a 32-bit system) or larger. Data alignment means putting the data at a memory address equal to some multiple of the word size, which increases the system’s performance due to the way the CPU handles memory. To align the data, it may be necessary to insert some meaningless bytes between the end of the last data structure and the start of the next, which is data structure padding.
从这段解释我们可以知道字节对齐的原因是:
+ 加快CPU访问内存中数据的速度;如果将数据存放在偶地址开始那么读出32bit变量时,仅仅需要一个周期,反之放在奇数地址之上需要两个周期才能读出。
+ 可以简化CPU和内存之间的接口。

每个特定的编译器都有自己默认的对齐系数,可以通过编译命令#pragma pack(n)指定对齐系数,其中n=1,2,4,8,16.

实例

结构体大小
//struct.cc
#include <iostream>

using namespace std;

struct stu1 {
    int i;
    char c;
    int j;
};

struct stu2 {
    char c;
    int i;
    char a;
};

struct stu3 {
    char c;
    char a;
    int i;
};

struct stu4 {
    int arr[0];
};

struct stu5 {
    char *c;
};

struct stu6 {
    char *c;
    int i;
};

struct stu7 {
    double i;
    char c;
};

struct stu8 {
    struct stu7 stu7Ojbect;
    double i;
};

int main (int argc, char *argv[])
{
    cout << "int = " << sizeof(int) << ", float = " << sizeof(float)
        << ", long = " << sizeof(long) << ", double = " << sizeof(double)
        << ", long long = " << sizeof (long long) << endl;
    cout << "the size of stu1 is " << sizeof(stu1) << endl;
    cout << "the size of stu2 is " << sizeof(stu2) << endl;
    cout << "the size of stu3 is " << sizeof(stu3) << endl;
    cout << "the size of stu4 is " << sizeof(stu4) << endl;
    cout << "the size of stu5 is " << sizeof(stu5) << endl;
    cout << "the size of stu6 is " << sizeof(stu6) << endl;
    cout << "the size of stu7 is " << sizeof(stu7) << endl;
    cout << "the size of stu8 is " << sizeof(stu8) << endl;  

    return 0;
}

在linux 64bit上以32位方式进行编译,结果如下:

$g++ -m struct.cc -o struct
$./struct
int = 4, float = 4, long = 4, double = 8, long long = 8
the size of stu1 is 12
the size of stu2 is 12
the size of stu3 is 8
the size of stu4 is 0
the size of stu5 is 4
the size of stu6 is 8
the size of stu7 is 12
the size of stu8 is 20

在linux 64bit上编译,结果如下:

$g++ struct.cc -o struct
$./struct
int = 4, float = 4, long = 8, double = 8, long long = 8
the size of stu1 is 12
the size of stu2 is 12
the size of stu3 is 8
the size of stu4 is 0
the size of stu5 is 8
the size of stu6 is 16
the size of stu7 is 16
the size of stu8 is 24

从上面的代码和运行结果中我们可以得出结论:
* 一个结构体中对齐方式是按照最长的基本类型为基准的。
- 比如,struct stu1中最长的是int,因此按照4字节对齐;而struct stu6最长是int *,在64位平台下按照8字节对齐。
- 按照4字节对齐时,不到4字节时,补齐另外的字节,比如struct stu2。8字节对齐时,依次类推。
* 需要注意的是柔性数组struct stu4中长度为0的数组并不占用空间,即sizeof(struct stu4)值为0,柔性数组主要用于实现动态的数组或者空间管理,在Linux Kernel以及redis的底层sds实现中均有体现。

类的大小

类的大小稍微复杂一些,需要考虑继承和虚函数问题,但是搞懂了虚函数问题,这个问题其实非常容易理解。关于虚函数的原理,可以参考皓叔的这篇博文C++虚函数表解析

#include <iostream>

using namespace std;

class nullClass
{
public:
    nullClass();
    ~nullClass();
};

class nullClassVirtual
{
public:
    nullClassVirtual();
    virtual ~nullClassVirtual();//虚函数需要占据一个指针的大小,64bits机器上是8字节
};

class staticClass {
public:
    static int i;
};

class staticConstClass {
    static const int i;
};

class Base
{
public:
    Base();
    virtual ~Base(); //虚函数需要占据一个指针大小,64bits机器上是8字节
    void set_num (int num)
    {
      a = num;
    }
private:
    int a;
    char *p;
    char c;
};

class Drive : public Base
{
public:
    Drive() : Base(){}
    ~Drive(){};
};

int main (int argv, char *argc[])
{
    cout << "the size of pointer is " << sizeof(int *) << endl;
    cout << "the size of nullClass is " << sizeof(nullClass) << endl;
    cout << "the size of nullClassVirtual " << sizeof(nullClassVirtual) << endl;
    cout << "the size of staticClass " << sizeof(staticClass) << endl;
    cout << "the size fo staticConstClass " << sizeof(staticConstClass) << endl;
    cout << "the size of Base is " << sizeof(Base) << endl;
    cout << "the size of Drive is " << sizeof(Drive) << endl;

    return 0;
}

在Linux 64bit的机器上分别以32位和64位的方式编译和运行

$g++ -m32 class.cc -o class
$./class
the size of pointer is 4
the size of nullClass is 1
the size of nullClassVirtual 4
the size of staticClass 1
the size fo staticConstClass 1
the size of Base is 16
the size of Drive is 16
  • 首先空类的大小1,这是因为在实例化的过程中每个实例在内存中都得有一个独一无二的地址,为了达到这个目的,编译器会给空类隐含加一个字节。详见stakcoverflow: Why is the size of an empty class in C++ not zero?
  • 对于空类,但是析构函数是virtual类型,该函数在基本的虚函数表中占用一项,因此szieof(nuullClassVirtual)大小为4.
  • 对于类中包含static/ static const成员的类,该静态成员不影响类的大小,该成员之友一个实例存在,无论类是否被实例化。
  • 对于Base类,大小为4(虚函数) + 4(int a) + 4(char *p) + 4(char c,虽然char大小为1,但是此处按照4字节对齐) = 16
  • 对于Drive类,继续了基类,因此大小至少为16,但是除此之外Drive类中不包含其他成员。

Linux 64bit下编译

$g++ class.cc -o class
$./class
the size of pointer is 8
the size of nullClass is 1
the size of nullClassVirtual 8
the size of staticClass 1
the size fo staticConstClass 1
the size of Base is 32
the size of Drive is 32
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值