服务端视角的C++从入门到精通(二十)

94 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情

讲讲sizeof(下)

之前的文章中曾经提到过,sizeof可以计算结构体和类的大小,那么这篇文章里我们就详细讲一下这里面的坑。

先看一下下面这段代码:

#include <iostream>
using namespace std;
int main() {
    string strArr1[]={"Trend", "Micro", "Soft"};
    cout << sizeof(string) << endl;
    
    return 0;
}

按照咱们之前对char数组分析的套路来看,答案应该是(5+1)+(5+1)+(4+1)=17(5+1)+(5+1)+(4+1)=17,但实际上输出的却是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,计算方式涉及到内存对齐问题。要判断一个结构体的大小,可以分为以下三步进行:

  1. x = min{系统决定(win=8, linux=4或8), 结构体中是基本数据类型最大成员的大小, #pragma pack(n)预编译指令指定的大小(n∈{1,2,4,8,16})}
  2. 除了第一个成员外,其他成员相对于结构体首地址的偏移量必须满足(1) offset = a × min{x, 自身大小}(a是自然数)(2) offset >= 前一个成员的偏移 + 前一个成员的大小
  3. 结构体整体大小必须是x的整数倍

我们对照上面的例子,来一步步分析一下:

第一步,假定是Windows系统,x = min{8, sizeof(uint64_t) = 8} = 8。

第二步,

  1. a相对于结构体首地址的偏移是0,大小是1
  2. b的偏移量是min{x = 8, sizeof(uint32_t) = 4} = 4的整数倍,这里由于a的偏移 + a的大小 = 1所以应该取不小于1的最小的4的倍数即4
  3. c的偏移量是min{x = 8, sizeof(uint8_t) = 1} = 1的整数倍,这里由于b的偏移 + b的大小 = 8所以应该取不小于8的最小的1的倍数即8
  4. d是min{x = 8, sizeof(uint64_t) = 8} = 8的整数倍,这里由于c的偏移 + c的大小 = 9所以应该取不小于9的最小的8的倍数即16;大小的话,这里由于是长度为0的数组,所以其实不占空间,即实际空间为0

第三步,按照前两步的计算,可以知道结构体的大小是16,是x的整数倍,符合要求。

所以最终sizeof(Obj)的结果就是16。