c语言格式对齐填充
Prerequisite:
先决条件:
We know that a struct size is not only the summation of all the data members, rather it's the minimum sum guaranteed. The compiler adds some padding for data member alignment.
我们知道,结构大小不仅是所有数据成员的总和,而且是保证的最小总和。 编译器为数据成员对齐添加了一些填充。
In the C++ class, things are exactly the same as a struct. But there are a few more things.
在C ++类中,事物与结构完全相同。 但是还有更多的事情。
Firstly, while in C++ there are member functions, static data members. Do those have any contribution to the size of the class, objects?
首先,在C ++中有成员函数,即静态数据成员。 这些对类,对象的大小有贡献吗?
The answer is no. Only the non-static data members contribute to the size of class and objects. This is because static members have only one instance which is shared among all objects. And normal member functions are like executable code which does not have size like data members.
答案是不。 只有非静态数据成员才有助于类和对象的大小。 这是因为静态成员只有一个实例,该实例在所有对象之间共享。 普通成员函数就像可执行代码,没有像数据成员那样大小。
Like in the following class,
像下面的课一样
class A {
private:
static int i;
int a;
char b;
public:
A()
{
a = 0;
b = '#';
}
A(int aa, char bb)
{
a = aa;
b = bb;
}
int get_int()
{
cout << a << endl;
return a;
}
char get_char()
{
cout << b << endl;
return b;
}
};
Size of the class should be sum of all the non-static data member+ padding, which is like below:
类的大小应为所有非静态数据成员+填充的总和,如下所示:
![C++ | size of a class (1)](https://i-blog.csdnimg.cn/blog_migrate/37319aaf90d9f585d0853f5edc0e36c0.png)
Above is the alignment of class A and that's why the size of the class is 8 Bytes. Static data members and member functions have no contribution.
上面是A类的对齐方式,这就是为什么该类的大小为8 Bytes的原因 。 静态数据成员和成员函数没有贡献。
编译器如何添加填充? (How compiler adds padding?)
Now the question is how compiler adds padding and align? The method is compiler dependent and kind of greedy. It aligns till the boundary of maximum memory allocated.
现在的问题是编译器如何添加填充和对齐? 该方法取决于编译器并且有点贪婪。 对齐直到分配的最大内存边界。
Here we find that max memory allocated is 8 Bytes, thus all the data members acquire 8 Bytes and the total size is 32 Bytes. Now the question is will it happen every time similarly?
在这里,我们发现分配的最大内存为8字节,因此所有数据成员都获取8字节,总大小为32字节。 现在的问题是,是否每次都会同样发生?
Is it like the number of data members * max datatype size?
就像数据成员数*最大数据类型大小一样吗?
The answer is no. It will try to align optimally keeping the same order. To check an example please follow the article on structure size in C. Also, later in this article, we have instances of such.
答案是不。 它将尝试最佳对齐以保持相同顺序。 要查看示例,请阅读有关C语言中结构大小的文章。此外,在本文的稍后部分,我们将提供这样的实例。
派生类的大小 (Size of a derived class)
What is the size of a derived class? Of course, a derived class has all data members of the base class it inherits and does it has its own copied of those data members too. Thus size should be the size of base class data members + size of derived class data members.
派生类的大小是多少? 当然,派生类具有其继承的基类的所有数据成员,并且它也具有这些数据成员的自己的副本。 因此,大小应为基类数据成员的大小+派生类数据成员的大小。
Let's check the below code and the output.
让我们检查以下代码和输出。
In the above structure, we find that the size is 24 Bytes though the same data members have been used. This is due to the change in the order of the member declaration. In this case, the alignment and padding would be like below:
在上面的结构中,我们发现尽管使用了相同的数据成员,但大小为24字节。 这是由于成员声明顺序的更改。 在这种情况下,对齐方式和填充将如下所示:
#include <bits/stdc++.h>
using namespace std;
class Base {
protected:
static int i;
int a;
char b;
public:
Base()
{
a = 0;
b = '#';
}
Base(int aa, char bb)
{
a = aa;
b = bb;
}
int get_int()
{
cout << a << endl;
return a;
}
char get_char()
{
cout << b << endl;
return b;
}
};
class Derived : public Base {
private:
int c;
char d;
public:
Derived()
{
c = 0;
d = '#';
}
Derived(int cc, char dd)
{
c = cc;
d = dd;
}
int get_int()
{
cout << c << endl;
return c;
}
char get_char()
{
cout << d << endl;
return d;
}
};
int main()
{
Base b;
Derived d;
printf("Size of class Base: %lu\n", sizeof(Base));
printf("Size of object b: %lu\n", sizeof(b));
printf("Size of class Derived: %lu\n", sizeof(Derived));
printf("Size of object d: %lu\n", sizeof(d));
return 0;
}
Output:
输出:
Size of class Base: 8
Size of object b: 8
Size of class Derived: 16
Size of object d: 16
So here the size of the base class object is 8 bytes, whereas the size of the derived class object is 16 Bytes.
因此,这里的基类对象的大小为8个字节,而派生类对象的大小为16个字节。
For the base class it's similar like below:
对于基类,它类似于以下内容:
![C++ | size of a class (2)](https://i-blog.csdnimg.cn/blog_migrate/556a868a29b85735acd6c83e3c9fc59d.png)
While for the derived class it's like:
而对于派生类,它就像:
![C++ | size of a class (3)](https://i-blog.csdnimg.cn/blog_migrate/4e22f00bcfcd1cab79c2c5673b08eefd.png)
So the thing is the order of data members are being maintained. And since we know that the base class constructor is invoked first, that's why the base class members come first.
因此,关键是要维护数据成员的顺序。 而且由于我们知道首先调用基类构造函数,所以这就是基类成员首先出现的原因。
Now let's change the order of data member in the derived class and check the size of the class & object.
现在,让我们更改派生类中数据成员的顺序,并检查类和对象的大小。
#include <bits/stdc++.h>
using namespace std;
class Base {
protected:
static int i;
int a;
char b;
public:
Base()
{
a = 0;
b = '#';
}
Base(int aa, char bb)
{
a = aa;
b = bb;
}
int get_int()
{
cout << a << endl;
return a;
}
char get_char()
{
cout << b << endl;
return b;
}
};
class Derived : public Base {
private:
char d;
int c;
public:
Derived()
{
c = 0;
d = '#';
}
Derived(int cc, char dd)
{
c = cc;
d = dd;
}
int get_int()
{
cout << c << endl;
return c;
}
char get_char()
{
cout << d << endl;
return d;
}
};
int main()
{
Base b;
Derived d;
printf("Size of class Base: %lu\n", sizeof(Base));
printf("Size of object b: %lu\n", sizeof(b));
printf("Size of class Derived: %lu\n", sizeof(Derived));
printf("Size of object d: %lu\n", sizeof(d));
return 0;
}
Output:
输出:
Size of class Base: 8
Size of object b: 8
Size of class Derived: 12
Size of object d: 12
Just changing the order of member we found that derived class is having size 12 Bytes now. So there must be some better alignment now.
只需更改成员的顺序,我们发现派生类的大小现在为12个字节。 因此,现在必须进行更好的调整。
So, as we can think of compiler went for greedy alignment and now it's able to align optimally (Remember compiler can’t change the order of data member).
因此,正如我们可以想到的那样,编译器进行了贪婪对齐,现在它可以进行最佳对齐(记住编译器无法更改数据成员的顺序)。
![C++ | size of a class (4)](https://www.includehelp.com/cpp-tutorial/Images/size-of-a-class-4.jpg)
Above is the alignment for the Derived class and now the size is 12 Bytes, instead of 16 because of the above alignment. We saw that compiler keeps aligning greedily & that's why it aligned char b of base class member & char d, which is its member, in the same row. When it tried to align int c, it could not as only 2 bytes were left. But instead of int, if it was char only then it would have aligned in the same line.
上面是Derived类的对齐方式,由于上面的对齐方式,现在的大小为12个字节,而不是16个字节。 我们看到编译器保持贪婪地对齐,这就是为什么它在同一行中对齐基类成员的char b和其成员char d 。 当它尝试对齐int c时 ,它不能,因为只剩下2个字节。 但不是INT,如果它是焦炭才把它会在同一线上。
虚拟关键字及其对大小的影响 (The virtual keyword and its effect on size)
We know in the derived class it can inherit the base class as virtual too. What would be the size of the derived class in that case? Will there be any changes?
我们知道,在派生类中,它也可以继承虚拟类的基类。 在这种情况下,派生类的大小是多少? 会有变化吗?
The answer is yes. There will be an additional 8 bytes which is nothing but the size of VTPR (Virtual Table pointer)
答案是肯定的。 将有一个额外的8个字节,不过就是VTPR(虚拟表指针)的大小
So, for the first derived class example, we got 16 Bytes, but here we have added the virtual keyword and got size 24 Bytes which is due to the size of VTPR.
因此,对于第一个派生类示例,我们获得了16个字节,但是由于VTPR的大小,我们在这里添加了virtual关键字并获得了24个字节的大小。
#include <bits/stdc++.h>
using namespace std;
class Base {
protected:
static int i;
int a;
char b;
public:
Base()
{
a = 0;
b = '#';
}
Base(int aa, char bb)
{
a = aa;
b = bb;
}
int get_int()
{
cout << a << endl;
return a;
}
char get_char()
{
cout << b << endl;
return b;
}
};
class Derived : virtual public Base {
private:
char d;
int c;
public:
Derived()
{
c = 0;
d = '#';
}
Derived(int cc, char dd)
{
c = cc;
d = dd;
}
int get_int()
{
cout << c << endl;
return c;
}
char get_char()
{
cout << d << endl;
return d;
}
};
int main()
{
Base b;
Derived d;
printf("Size of class Base: %lu\n", sizeof(Base));
printf("Size of object b: %lu\n", sizeof(b));
printf("Size of class Derived: %lu\n", sizeof(Derived));
printf("Size of object d: %lu\n", sizeof(d));
return 0;
}
Output:
输出:
Size of class Base: 8
Size of object b: 8
Size of class Derived: 24
Size of object d: 24
So, here we got the idea of a normal class and object size. We learnt how the compiler aligns the data members and add padding. Also, we extended the discussion to the size of the derived class.
因此,这里我们有了一个普通的类和对象大小的想法。 我们了解了编译器如何对齐数据成员并添加填充。 同样,我们将讨论扩展到派生类的大小。
To end the discussion let me just throw a brain teaser. What do you think would be the size of an empty class?
为了结束讨论,我只想动脑子。 您认为空班级的人数多少?
Do you think it's 0?
你认为是0吗?
#include <bits/stdc++.h>
using namespace std;
class A {
};
int main()
{
printf("Size of class A: %lu\n", sizeof(A));
return 0;
}
Output:
输出:
Size of class A: 1
Well, the size of the empty class is not 0. This is actually to ensure that two different objects will have different addresses.
嗯,空类的大小不为0。这实际上是为了确保两个不同的对象具有不同的地址。
c语言格式对齐填充