携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情
讲讲sizeof(下)
之前的文章中曾经提到过,sizeof可以计算结构体和类的大小,那么这篇文章里我们就详细讲一下这里面的坑。
先看一下下面这段代码:
#include <iostream>
using namespace std;
int main() {
string strArr1[]={"Trend", "Micro", "Soft"};
cout << sizeof(string) << endl;
return 0;
}
按照咱们之前对char数组分析的套路来看,答案应该是,但实际上输出的却是8。这是为什么呢?首先要明确的是,string是C++里面对于字符串常用操作的一个封装类,他不止包含简单的char数组,还包含了一些辅助信息。这里由于不同的库对于string类的实现略有区别,所以对于上面这段代码,在不同的平台上可能会得到不同的输出。
再来看下面这一段代码:
#include <cstdio>
#include <cstdint>
void testStructSizeof()
{
struct Obj
{
char a;
uint32_t b;
uint8_t c;
uint64_t d[0];
};
printf("sizeof(Obj)=%d\n", sizeof(Obj));
}
int main() {
testStructSizeof();
return 0;
}
这里Obj结构体的的大小是16,计算方式涉及到内存对齐问题。要判断一个结构体的大小,可以分为以下三步进行:
- x = min{系统决定(win=8, linux=4或8), 结构体中是基本数据类型的最大成员的大小,
#pragma pack(n)预编译指令指定的大小(n∈{1,2,4,8,16})} - 除了第一个成员外,其他成员相对于结构体首地址的偏移量必须满足(1) offset = a × min{x, 自身大小}(a是自然数)(2) offset >= 前一个成员的偏移 + 前一个成员的大小
- 结构体整体大小必须是x的整数倍
我们对照上面的例子,来一步步分析一下:
第一步,假定是Windows系统,x = min{8, sizeof(uint64_t) = 8} = 8。
第二步,
a相对于结构体首地址的偏移是0,大小是1b的偏移量是min{x = 8,sizeof(uint32_t)= 4} = 4的整数倍,这里由于a的偏移 +a的大小 = 1所以应该取不小于1的最小的4的倍数即4c的偏移量是min{x = 8,sizeof(uint8_t)= 1} = 1的整数倍,这里由于b的偏移 +b的大小 = 8所以应该取不小于8的最小的1的倍数即8d是min{x = 8,sizeof(uint64_t)= 8} = 8的整数倍,这里由于c的偏移 +c的大小 = 9所以应该取不小于9的最小的8的倍数即16;大小的话,这里由于是长度为0的数组,所以其实不占空间,即实际空间为0
第三步,按照前两步的计算,可以知道结构体的大小是16,是x的整数倍,符合要求。
所以最终sizeof(Obj)的结果就是16。