是否有可能在编译器对齐之前获得 class/struct 的原始大小?
Is it possible to get the original size of the class/struct before compiler align it?
我正在寻找一种方法来在编译器对齐它之前获取 struct/class 的原始大小(更清楚地说,让我们说 struct/class 的成员字段的总和),如下所示:
struct Foo{
char c;
// the compiler will appen 3 bytes here
int i;
};
sizeof(Foo) returns 8 但原来的大小是 5 .
假设我们要编写一个名为 orig_sizeof()
的模板函数或宏
template <class t>
size_t orig_sizeof(t)
{
// calculate the sum of the fields of t
}
当然sizeof
是内部宏,没有源码的关键字宏
一种可能的方法是使用 __attribute__
或 #pragma
更改结构对齐,而不是在将对齐恢复为默认值后使用 sizeof 获取大小(也许 c++11 的 decltype 可以很有用!),关于有用的实现有什么想法吗?
编辑:
我正在尝试编写一个优化的库,该库不接受未优化的 struct/class 作为参数,方法是将 sizeof(type) 与 orig_sizeof(type) 进行比较,并要求用户重新调整字段以获得更好的性能,如果可能
没有。 C++ 不提供该功能。将来,当众多反射提案中的一个进入标准时,您可能能够获得所有成员的规模。然而,它本质上是毫无意义的,并且不可能做你想做的事。原因如下:
1) 在您的示例中,无论成员的顺序如何,struct {char; int; };
的长度始终为 8 个字节。总是会有 3 个字节的填充:在 char
和 int
之间,在最后,在 int
和 char
之间有 1 个,在最后有 2 个......它是无法使用标准 C++ 构建 "effectivelly packed" 结构。
2) 继承。编译器可以为子成员重用父结构中的填充。其中的一个子集是空基优化,它可以使整个对象的大小小于其基和成员的总和。或不。 EBO 不是强制性的。尝试确定 EBO 是否只是没有被触发并且结构是 "effectivelly packed" 或者它被触发并且你在某处有 2 个杂散字节的填充很有趣。
3) 动态调度设施。通常它是 class 中的另一个不可见指针成员(或多个在多重继承的情况下),它将向 class 添加自己的对齐要求。然后 (1) 适用。更糟糕的是,您无法更改这些指针的放置位置。
您可以在单独的 header 中定义结构,并使用条件编译进行打包:
struct
#ifdef pack
__attribute__((packed))
PackedFoo
#else
Foo
#endif
{
char c;
int i;
};
然后使用预处理器包含结构的打包和解包版本:
#include "foo.hpp"
#define pack
#include "foo.hpp"
这样您就可以观察到两种尺寸,就好像它们是同一类型一样:
//custom sizeof for packed representation
#define sizeof_packed(type) sizeof(Packed##type)
int main(){
std::cout << sizeof(Foo) << '\n'; //prints 8
std::cout << sizeof_packed(Foo) << '\n'; //prints 5
}
我正在寻找一种方法来在编译器对齐它之前获取 struct/class 的原始大小(更清楚地说,让我们说 struct/class 的成员字段的总和),如下所示:
struct Foo{
char c;
// the compiler will appen 3 bytes here
int i;
};
sizeof(Foo) returns 8 但原来的大小是 5 .
假设我们要编写一个名为 orig_sizeof()
的模板函数或宏template <class t>
size_t orig_sizeof(t)
{
// calculate the sum of the fields of t
}
当然sizeof
是内部宏,没有源码的关键字宏
一种可能的方法是使用 __attribute__
或 #pragma
更改结构对齐,而不是在将对齐恢复为默认值后使用 sizeof 获取大小(也许 c++11 的 decltype 可以很有用!),关于有用的实现有什么想法吗?
编辑: 我正在尝试编写一个优化的库,该库不接受未优化的 struct/class 作为参数,方法是将 sizeof(type) 与 orig_sizeof(type) 进行比较,并要求用户重新调整字段以获得更好的性能,如果可能
没有。 C++ 不提供该功能。将来,当众多反射提案中的一个进入标准时,您可能能够获得所有成员的规模。然而,它本质上是毫无意义的,并且不可能做你想做的事。原因如下:
1) 在您的示例中,无论成员的顺序如何,struct {char; int; };
的长度始终为 8 个字节。总是会有 3 个字节的填充:在 char
和 int
之间,在最后,在 int
和 char
之间有 1 个,在最后有 2 个......它是无法使用标准 C++ 构建 "effectivelly packed" 结构。
2) 继承。编译器可以为子成员重用父结构中的填充。其中的一个子集是空基优化,它可以使整个对象的大小小于其基和成员的总和。或不。 EBO 不是强制性的。尝试确定 EBO 是否只是没有被触发并且结构是 "effectivelly packed" 或者它被触发并且你在某处有 2 个杂散字节的填充很有趣。
3) 动态调度设施。通常它是 class 中的另一个不可见指针成员(或多个在多重继承的情况下),它将向 class 添加自己的对齐要求。然后 (1) 适用。更糟糕的是,您无法更改这些指针的放置位置。
您可以在单独的 header 中定义结构,并使用条件编译进行打包:
struct
#ifdef pack
__attribute__((packed))
PackedFoo
#else
Foo
#endif
{
char c;
int i;
};
然后使用预处理器包含结构的打包和解包版本:
#include "foo.hpp"
#define pack
#include "foo.hpp"
这样您就可以观察到两种尺寸,就好像它们是同一类型一样:
//custom sizeof for packed representation
#define sizeof_packed(type) sizeof(Packed##type)
int main(){
std::cout << sizeof(Foo) << '\n'; //prints 8
std::cout << sizeof_packed(Foo) << '\n'; //prints 5
}