c++ - 是否有任何可移植的方法来确保在不使用 c++11 填充字节的情况下定义结构?
问题描述
让我们考虑以下任务:我的 C++ 模块作为嵌入式系统的一部分接收 8 个字节的数据,例如:uint8_t data[8]。第一个字节的值决定了其余部分的布局(20-30 不同)。为了有效地获取数据,我将为每个布局创建不同的结构并将每个结构放入一个联合中,并通过如下指针直接从我的输入地址读取数据:
struct Interpretation_1 {
uint8_t multiplexer;
uint8_t timestamp;
uint32_t position;
uint16_t speed;
};
// and a lot of other struct like this (with bitfields, etc..., layout is not defined by me :( )
union DataInterpreter {
Interpretation_1 movement;
//Interpretation_2 temperatures;
//etc...
};
...
uint8_t exampleData[8] {1u, 10u, 20u,0u,0u,0u, 5u,0u};
DataInterpreter* interpreter = reinterpret_cast<DataInterpreter*>(&exampleData);
std::cout << "position: " << +interpreter->movement.position << "\n";
我遇到的问题是,编译器可以在解释结构中插入填充字节,这扼杀了我的想法。我知道我可以使用
- 使用 gcc:
struct MyStruct{} __attribute__((__packed__));
- 使用 MSVC:我可以使用
#pragma pack(push, 1) MyStruct{}; #pragma pack(pop)
- 与铿锵:?(我可以检查一下)
但是有没有可移植的方法来实现这一点?我知道 c++11 有例如 alignas 用于对齐控制,但我可以用它来做这个吗?我必须使用 c++11,但如果有更高版本的 c++ 更好的解决方案,我会很感兴趣。
解决方案
但是有没有可移植的方法来实现这一点?
不,没有(标准)方法可以“制作”一种在 C++ 中具有填充而不具有填充的类型。所有对象都至少按照它们的类型要求对齐,如果对齐与之前的子对象不匹配,那么就会有填充,这是不可避免的。
此外,还有另一个问题:您正在通过重新解释的指针访问,该指针不指向兼容类型的对象。程序的行为是未定义的。
我们可以得出结论,类通常不适用于表示任意二进制数据。打包结构是非标准的,并且它们在具有不同整数表示(字节字节序)的不同系统之间也不兼容。
有一种方法可以检查一个类型是否包含填充:将子对象的大小与完整对象的大小进行比较,并递归地对每个成员执行此操作。如果大小不匹配,则有填充。然而,这非常棘手,因为 C++ 的反射能力极少,因此您需要使用硬编码或元编程。
鉴于这样的检查,您可以在假设不成立的系统上使编译失败。
另一个方便的工具是std::has_unique_object_representations
(自 C++17 起),对于所有具有填充的类型,它始终为 false。但请注意,例如,对于包含浮点数的类型,它也是错误的。只有返回 true 的类型才能有意义地比较与 的相等性std::memcmp
。
推荐阅读
- android - Ionic 3 - 在 android 上为选定的组件使用 iOS 样式
- sql - 如何检查所有当前行的列是否为空或空白('')?
- excel - 在 VBA 中将“dddd”与“long date”结合会产生奇怪的结果
- android - 在模拟器 GenyMotion 上加载反应本机问题
- java - 如何跳过 xml 标签内的文本验证?
- jquery - 如何在 jquery 模板中隐藏一列
- wpf - 单击任务栏中的任何窗口时,Wpf会打开所有窗口
- mongodb - 限制 Mongoose 在字段后返回数据
- python - 确保草图/流式算法(countSketch)的性能
- mysql - 如何获得前 3 名(有重复项)