确定 class 的静态变量的总大小?
Determine total size of static variables of class?
在 C++ 中,我可以使用 sizeof(my_class)
确定 class 对象的大小。
但是,对于 class 的静态部分似乎没有等效的运算符。
在 C++ 中有类似 sizeof(static my_class)
的东西吗?
您不会在标准 C++ 中找到合法的或 portable1 方法来执行此操作,但您当然可以使用特定于平台的工具来检查二进制来估计全局数据的大小。
在 Unix 平台上,您可以使用多种 ELF 格式阅读工具中的一种来转储符号 table 以及大小。例如,类似于:
nm --demangle --print-size a.out | egrep -i ' [bdgsr] '
将转储 .bss
、.data
、.rodata
和相关部分 中所有全局数据的大小(作为输出中的第二个字段) 2。
--demangle
参数从 C++ 错位名称中为您提供人类可读的名称。管道末尾的 egrep
将符号限制为通常用于静态变量的符号(即,它省略了函数的符号)。鉴于以下 class:
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
来限制特定的 classes.
请注意 Foo::some_const_string
的大小为 8,尽管 hello, world?
的值为 14 个字符(包括终止空值)。事实上,您会发现任何 const char *
或任何静态指针在 64 位平台上的大小都是 8,因为这是指针本身的大小。 字符串文字(字符h,e,l,l,o,...
)的实际数据存储在其他地方,nm
未报告此大小。通常确定字符串文字的大小 并且可能没有直接的答案(即,几个 classes 可能共享相同的底层文字数据)。如果您真的想将其包含在您的会计中,您可能必须编写类似 readelf
的脚本。
您也可以尝试现有的二进制大小调整实用程序,例如 Bloaty McBloatface,尽管快速浏览自述文件似乎表明它可能只是提供与上面相同的信息(例如,它不会似乎可以处理 "string literal" 问题)。
1 例如, 提到了一种在运行时采用 "first" 和 "last" 静态的差异来估计大小,但除了 未定义的行为 它不太可能在实践中工作,因为全局变量分布在二进制文件的各个部分,例如 .bss
、.data
、.rodata
和它们的其他变体,因此对于许多 class 来说,简单的减法几乎肯定会 return 是错误的结果。
2 特别是,当我说 "related" 时,我的意思是它会转储 "small" 已初始化和未初始化部分的大小以及默认值那些。
在 C++ 中,我可以使用 sizeof(my_class)
确定 class 对象的大小。
但是,对于 class 的静态部分似乎没有等效的运算符。
在 C++ 中有类似 sizeof(static my_class)
的东西吗?
您不会在标准 C++ 中找到合法的或 portable1 方法来执行此操作,但您当然可以使用特定于平台的工具来检查二进制来估计全局数据的大小。
在 Unix 平台上,您可以使用多种 ELF 格式阅读工具中的一种来转储符号 table 以及大小。例如,类似于:
nm --demangle --print-size a.out | egrep -i ' [bdgsr] '
将转储 .bss
、.data
、.rodata
和相关部分 中所有全局数据的大小(作为输出中的第二个字段) 2。
--demangle
参数从 C++ 错位名称中为您提供人类可读的名称。管道末尾的 egrep
将符号限制为通常用于静态变量的符号(即,它省略了函数的符号)。鉴于以下 class:
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
来限制特定的 classes.
请注意 Foo::some_const_string
的大小为 8,尽管 hello, world?
的值为 14 个字符(包括终止空值)。事实上,您会发现任何 const char *
或任何静态指针在 64 位平台上的大小都是 8,因为这是指针本身的大小。 字符串文字(字符h,e,l,l,o,...
)的实际数据存储在其他地方,nm
未报告此大小。通常确定字符串文字的大小 readelf
的脚本。
您也可以尝试现有的二进制大小调整实用程序,例如 Bloaty McBloatface,尽管快速浏览自述文件似乎表明它可能只是提供与上面相同的信息(例如,它不会似乎可以处理 "string literal" 问题)。
1 例如,.bss
、.data
、.rodata
和它们的其他变体,因此对于许多 class 来说,简单的减法几乎肯定会 return 是错误的结果。
2 特别是,当我说 "related" 时,我的意思是它会转储 "small" 已初始化和未初始化部分的大小以及默认值那些。