您不会在标准 C++ 中找到合法或可移植的1 方法来执行此操作,但您当然可以使用特定于平台的工具检查二进制文件以估计全局大小数据。
在 Unix 平台上,您可以使用多种 ELF 格式读取工具中的一种来转储符号表和大小。例如,类似:
nm --demangle --print-size a.out | egrep -i ' [bdgsr] '
将转储.bss、.data、.rodata 和相关部分中所有全局数据的大小(作为输出中的第二个字段)2。
--demangle 参数从 C++ 错位名称中为您提供人类可读的名称。管道末尾的 egrep 将符号限制为通常用于静态变量的符号(即,它省略了函数的符号)。给定以下类:
class Foo {
static void StaticFunction();
void MemberFunction();
static int some_int_s;
static long some_zero_long;
static char some_char_array[];
static const char *some_const_string;
};
int Foo::some_int_s = 5;
char Foo::some_char_array[42];
const char* Foo::some_const_string = "hello, world?";
void Foo::StaticFunction() {
}
void Foo::MemberFunction() {
static double f = 0.5;
}
...并使用g++ 编译,上面给出的nm 命令输出:
0000000000000000 0000000000000004 D Foo::some_int_s
0000000000000000 000000000000002a B Foo::some_char_array
0000000000000008 0000000000000008 D Foo::some_const_string
0000000000000010 0000000000000008 d Foo::MemberFunction()::f
第二列是全局的大小:int 为 4 个字节,char[] 为 0x2a (42) 个字节,依此类推。请注意,它还包括函数局部静态变量,这可能是您想要的,因为它们像其他任何东西一样占用大小。您可以使用另一个grep 来限制特定的类。
请注意,Foo::some_const_string 的大小为 8,尽管 hello, world? 的值是 14 个字符(包括终止的 null)。事实上,您会发现任何const char * 或任何静态指针在64 位平台上的大小都是8,因为这是指针本身的大小。 字符串文字(字符h,e,l,l,o,...)的实际数据存储在其他地方,nm 不会报告此大小。通常确定字符串文字 is complex 的大小并且可能没有直接的答案(即,多个类可能共享相同的底层文字数据)。如果您真的想将其包含在您的会计中,您可能必须编写类似readelf 的脚本。
您也可以尝试现有的二进制大小调整实用程序,例如 Bloaty McBloatface,尽管快速浏览自述文件似乎表明它可能只是提供与上述相同的信息(例如,它似乎无法处理“字符串文字”问题)。
1 例如,a comment 提到了一种在运行时采用“first”和“last”静态变量的差异来估计大小的方法,但除了 未定义行为它不太可能在实践中起作用,因为全局变量分布在二进制文件的各个部分,例如.bss、.data、.rodata 和其他变体,所以简单的减法将几乎肯定会为许多类返回错误的结果。
2 特别是,当我说“相关”时,我的意思是除了默认部分之外,它还会转储“小”已初始化和未初始化部分的大小。