两成员结构是位压缩int的安全替代品吗? 我有一些C++代码,它通过网络发送一个代码为 UTIT32×T/的数组。由于我的协议发生了变化,我想用一对两个uint16\u ts替换此数组中的每个条目,如果可能,我希望在不更改通过网络发送的位数的情况下执行此操作。要将两个uint16\u t值组合成一个32位宽的值,一个明显的方法是将低级位打包到uint32\u t,并保持数组定义不变。因此,发件人的代码如下所示: uint32_t项目[ARR_大小]; 对于(标准::尺寸i=0;i>16;} 无效集_field1(uint16_tt v){field=(field&0xffff0000)|v;} 无效集_field2(uint16_tt v){field=(field&0x0000ffff)| v虽然我会扔掉任何不使数据项与uint32\u t大小相同的实现,但法律允许它们添加填充。有趣的是,你在位移位上使用某种大尾数,在结构上使用小尾数。确保发送方和接收方使用相同的顺序。@CAF哦,你说得对,如果我希望结构和位移位是等效的布局,我应该将field2放在uint32的高阶位,而不是低阶位。我修复了我的示例。我明白了,我本可以更清楚地了解我的目标。我不是为了让软件的早期版本与较新版本通信而寻求协议向后兼容性。我只希望新版本的协议发送与旧版本相同的字节数,而不是引入不必要的填充。 struct data_item_t { uint32_t field; uint16_t get_field1() const { return field; } uint16_t get_field2() const { return field >> 16; } void set_field1(uint16_t v) { field = (field & 0xffff0000) | v; } void set_field2(uint16_t v) { field = (field & 0x0000ffff) | v << 16; } }; static_assert(std::is_trivially_copyable<data_item_t>::value == true, ""); static_assert(sizeof(data_item_t) == sizeof(uint32_t), ""); static_assert(alignof(data_item_t) == alignof(uint32_t), "");

两成员结构是位压缩int的安全替代品吗? 我有一些C++代码,它通过网络发送一个代码为 UTIT32×T/的数组。由于我的协议发生了变化,我想用一对两个uint16\u ts替换此数组中的每个条目,如果可能,我希望在不更改通过网络发送的位数的情况下执行此操作。要将两个uint16\u t值组合成一个32位宽的值,一个明显的方法是将低级位打包到uint32\u t,并保持数组定义不变。因此,发件人的代码如下所示: uint32_t项目[ARR_大小]; 对于(标准::尺寸i=0;i>16;} 无效集_field1(uint16_tt v){field=(field&0xffff0000)|v;} 无效集_field2(uint16_tt v){field=(field&0x0000ffff)| v虽然我会扔掉任何不使数据项与uint32\u t大小相同的实现,但法律允许它们添加填充。有趣的是,你在位移位上使用某种大尾数,在结构上使用小尾数。确保发送方和接收方使用相同的顺序。@CAF哦,你说得对,如果我希望结构和位移位是等效的布局,我应该将field2放在uint32的高阶位,而不是低阶位。我修复了我的示例。我明白了,我本可以更清楚地了解我的目标。我不是为了让软件的早期版本与较新版本通信而寻求协议向后兼容性。我只希望新版本的协议发送与旧版本相同的字节数,而不是引入不必要的填充。 struct data_item_t { uint32_t field; uint16_t get_field1() const { return field; } uint16_t get_field2() const { return field >> 16; } void set_field1(uint16_t v) { field = (field & 0xffff0000) | v; } void set_field2(uint16_t v) { field = (field & 0x0000ffff) | v << 16; } }; static_assert(std::is_trivially_copyable<data_item_t>::value == true, ""); static_assert(sizeof(data_item_t) == sizeof(uint32_t), ""); static_assert(alignof(data_item_t) == alignof(uint32_t), "");,c++,struct,memory-alignment,C++,Struct,Memory Alignment,不应该存在任何实现定义的填充问题,但是根据端点的不同,表示形式之间会有差异。还要注意对齐方式会有所不同-例如,如果将值嵌入另一个结构中,这会变得相关 更一般地说,不清楚您试图实现的协议兼容性级别。我建议您要么决定允许在不同版本之间中断协议兼容性,要么非常明确地以可扩展和版本化的方式设置协议,以便不同版本的软件可以在这种情况下,您应该设计协议,使其独立于C++实现的定义良好,并以字节为单位的方式编写发送/接收代码,以避免出现临时性问题。 我根本看不到在改变表示的同时保持相同的数据大小能取得什么效果

不应该存在任何实现定义的填充问题,但是根据端点的不同,表示形式之间会有差异。还要注意对齐方式会有所不同-例如,如果将值嵌入另一个结构中,这会变得相关

更一般地说,不清楚您试图实现的协议兼容性级别。我建议您要么决定允许在不同版本之间中断协议兼容性,要么非常明确地以可扩展和版本化的方式设置协议,以便不同版本的软件可以在这种情况下,您应该设计协议,使其独立于C++实现的定义良好,并以字节为单位的方式编写发送/接收代码,以避免出现临时性问题。 我根本看不到在改变表示的同时保持相同的数据大小能取得什么效果

这很难看,类型不安全,并且依赖于硬编码的幻数

这是一个众所周知的习惯用法,也是我们从C开始使用位操作运算符的原因之一。这些数字中没有“魔力”

另一种选择是调用
std::memcpy
,只要你知道你的结束语。如果你担心的话,这也更容易概括

我想知道,通过定义一个“应该”与uint32\t大小完全相同的2成员结构,是否有可能完成同样的任务

不是使用两个成员的结构,但是可以使用2个
uint16\t
s数组来实现,这将保证它们之间没有填充

相反,您也可以根据需要使用2个成员,但要声明大小是最小的。至少这样,您可以保证它在编译时可以工作(这在当今大多数平台上都可以):

这是否等同于位压缩
uint32\u t
s?换句话说,当我使用struct data\u item\t时,items数组是否包含与使用
uint32\u t
和位压缩时相同的位

否,编译器可能会添加填充

或者这实际上是由我的编译器决定的,我需要像
\uuuuu attribute\uuuu((\uuu packed\uuuu))
这样的东西来保证吗


这就是该属性存在的理由(特别是对于不同的类型)。:-)

只需编写正确的访问器:

struct data_item_t {
    uint32_t field;
    uint16_t get_field1() const { return field; }
    uint16_t get_field2() const { return field >> 16; }
    void set_field1(uint16_t v) { field = (field & 0xffff0000) | v; }
    void set_field2(uint16_t v) { field = (field & 0x0000ffff) | v << 16; }
};
static_assert(std::is_trivially_copyable<data_item_t>::value == true, "");
static_assert(sizeof(data_item_t) == sizeof(uint32_t), "");
static_assert(alignof(data_item_t) == alignof(uint32_t), "");
结构数据项{ uint32_t字段; uint16_t get_field1()常量{return field;} uint16\u t get_field2()常量{return field>>16;} 无效集_field1(uint16_tt v){field=(field&0xffff0000)|v;}
无效集_field2(uint16_tt v){field=(field&0x0000ffff)| v虽然我会扔掉任何不使
数据项
uint32\u t
大小相同的实现,但法律允许它们添加填充。有趣的是,你在位移位上使用某种大尾数,在结构上使用小尾数。确保发送方和接收方使用相同的顺序。@CAF哦,你说得对,如果我希望结构和位移位是等效的布局,我应该将field2放在uint32的高阶位,而不是低阶位。我修复了我的示例。我明白了,我本可以更清楚地了解我的目标。我不是为了让软件的早期版本与较新版本通信而寻求协议向后兼容性。我只希望新版本的协议发送与旧版本相同的字节数,而不是引入不必要的填充。
struct data_item_t {
    uint32_t field;
    uint16_t get_field1() const { return field; }
    uint16_t get_field2() const { return field >> 16; }
    void set_field1(uint16_t v) { field = (field & 0xffff0000) | v; }
    void set_field2(uint16_t v) { field = (field & 0x0000ffff) | v << 16; }
};
static_assert(std::is_trivially_copyable<data_item_t>::value == true, "");
static_assert(sizeof(data_item_t) == sizeof(uint32_t), "");
static_assert(alignof(data_item_t) == alignof(uint32_t), "");