如何获取结构或类的尾随填充的大小
How to get the size the trailing padding of a struct or class?
sizeof
可用于获取结构或类的大小。 offsetof
可用于获取结构或类中字段的字节偏移量。
同样,有没有办法获取结构或类的尾随填充的大小?我正在寻找一种不依赖于结构布局的方法,例如要求最后一个字段具有特定名称。
对于背景,我正在写出一个结构到磁盘,但我不想写出尾随填充,所以我需要写入的字节数是大小减去尾随填充的大小。
澄清:不写入尾随填充的动机是保存输出字节。我不是在尝试保存内部填充,因为我不确定不对齐访问的性能影响,并且我希望编写代码维护成本低,以便在结构定义更改时不需要更改。
编译器在结构中填充字段的方式在标准中没有严格定义,因此它是一种自由选择和实现依赖。如果必须交换数据聚合,唯一的解决方案是避免任何填充。
这通常使用 #pragma pack(1)
完成。此杂注指示编译器将所有字段打包在 1 字节边界上。 它会减慢某些处理器的访问速度,但会使结构紧凑且在任何系统上定义良好,当然,没有任何填充。
指示包或等效项是执行此操作的规范方法。除此之外,我只能想到一个宏,如果成员数量是固定的或最大数量很少,比如
$ cat struct-macro.c && echo
#include<stdio.h>
using namespace std;
#define ASSEMBLE_STRUCT3(Sname, at, a, bt, b, ct, c) struct Sname {at a; bt b; ct c; };
int Sname##_trailingbytes() { return sizeof(struct Sname) - offsetof(Sname, c) - sizeof(ct); }
ASSEMBLE_STRUCT3(S, int, i1, int, i2, char, c)
int main()
{
printf("%dn", S_trailingbytes());
}
$ g++ -Wall -o struct-macro struct-macro.c && ./struct-macro
3
$
我想知道是否可以用 in C++ 的可变参数模板类做一些花哨的事情。但是我不太明白如何定义类/结构以及在没有宏的情况下再次提供偏移函数/常量 - 这将破坏目的。
填充可以在结构内的任何位置,除了在最开始的地方。没有禁用填充的标准方法,尽管某些#pragma pack
是常见的非标准扩展。
如果您想要一个可靠的可移植解决方案,您实际上应该做的是为结构编写序列化/反序列化例程。
像这样:
typedef
{
int x;
int y;
...
} mytype_t;
void mytype_serialize (uint8_t* restrict dest, const mytype_t* restrict src)
{
memcpy(dest, &src->x, sizeof(src->x)); dest += sizeof(src->x);
memcpy(dest, &src->y, sizeof(src->y)); dest += sizeof(src->y);
...
}
反之亦然。
请注意,填充是有原因的。如果摆脱它,则会牺牲执行速度以增加内存大小。
编辑
奇怪的方法,只需跳过尾随填充:
size_t mytype_serialize (uint8_t* restrict dest, const mytype_t* restrict src)
{
size_t size = offsetof(my_type_t, y); // assuming y is last object
memcpy(dest, src, size);
memcpy(dest+size, &src->y, sizeof(src->y));
size += sizeof(src->y);
return size;
}
您需要知道大小并对其执行有意义的操作,因为否则当您需要读回存储的数据时,您将无法知道存储数据的大小。
可能性:
#define BYTES_AFTER(st, last) (sizeof (st) - offsetof(st, last) - sizeof ((st*)0)->last)
正如这个(C99)方法一样:
#define BYTES_AFTER(st, last) (sizeof (st) - offsetof(st, last) - sizeof (st){0}.last)
另一种方法是通过一些非标准#pragma
或类似方式声明您的结构packed
。这也将照顾中间的填充。
不过,这两个都不漂亮。由于不同的对齐要求,不同系统之间的共享可能不起作用。使用非标准扩展是非标准的。
只需自己进行序列化即可。也许是这样的:
unsigned char buf[64];
mempcpy(mempcpy(mempcpy(buf,
&st.member_1, sizeof st.member_1),
&st.member_2, sizeof st.member_2),
&st.member_3, sizeof st.member_3);
mempcpy
是一个 GNU 扩展,如果它不可用,只需自己定义它:
static inline void * mempcpy (void *dest, const void *src, size_t len) {
return (char*)memcpy(dest, src, len) + len;
}
IMO,它使这样的代码更容易阅读。
- C++为构建时间获取QDateTime的可靠方法
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 在c++中用vector填充一个简单的动态数组
- 使用指针从C++中的数组中获取最大值
- 如何获取std::result_of函数的返回类型
- 如何在openssl-ecc中获取十六进制格式的私钥
- 使用Unreal C++获取VR耳机的世界位置/方向
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何使用用户输入在C++中正确填充2D数组
- 从C字符串中获取奇怪的字符串长度
- 为什么我的for循环不能正确获取argv
- Cryptopp:获取密码输入的填充字符串
- 无法获取已填充堆栈<char>的顶部元素
- 如何在类结束时获取填充的大小
- 填充字符数组的最佳方法(获取与cin.getline)
- 如何获取结构或类的尾随填充的大小
- 填充列表<>使用数组获取错误的数字
- 当从列表中获取值时,我填充其中的数组不返回任何值
- 使用发送消息填充列表框获取垃圾