在 C++ 的联合中动态分配内存给数组
Dynamically allocate memory to arrays in a union in C++
我正在使用 union 来填充 char 类型消息缓冲区中的一些消息字段。如果消息的长度不变,它就可以正常工作。请参阅下面的简化代码示例。
问题是,我的消息可以有可变长度。具体来说,const N
将在运行时决定。有没有办法通过为 buf
?
动态分配内存来继续使用联合
我正在探索智能指针,但到目前为止还没有成功。
const int N = 4;
struct repeating_group_t {
uint8_t field1;
uint8_t field2;
}rpt_group;
struct message_t
{
union
{
char buf[2 + 2*N];
struct {
uint8_t header;
uint8_t block_len;
std::array<repeating_group_t, N> group;
};
};
};
int main()
{
message_t msg;
msg.header = 0x32;
msg.block_len = 8;
for (auto i = 0; i < N; i++)
{
msg.group[i].field1 = i;
msg.group[i].field2 = 10*i;
}
// msg.buf is correctly filled
return 0;
}
您不能在运行时计算 N,因为 c 数组(您的 buf
)和 std::array
在其类型中都有大小信息。
此外 - 使用 union 进行(反)序列化不是一个好习惯 - 你的结构的大小将取决于它被编译的给定机器上所需的对齐等等...你可以添加 packed
属性来克服它,但你仍然有很多平台依赖性问题。
关于可变长度 - 您需要编写自定义(反)序列化程序来理解和 store/read 该大小信息以在另一端重新创建该容器。
您想将这些消息传递到哪里?
如评论所说,使用std::vector
。
int main() {
// before C++17 use char
std::vector<std::byte> v.
v.push_back(0x32);
v.push_back(8);
for (auto i = 0; i < N; i++) {
v.push_back(i);
const uint16_t a = 10 * i;
// store uint16_t in big endian
v.push_back(a >> 16);
v.push_back(a & 0xff);
}
}
对于自定义数据类型,您可以提供自己的流式或容器式容器和重载 operator>>
或您为数据类型选择的其他自定义函数。
struct Message{
std::vector<std::byte> v;
Message& push8(uint8_t t) { ... }
// push 16 bits little endian
Message& push16le(uint16_t t) { ... }
// push 16 bits big endian
Message& push16be(uint16_t t) { ... }
// etc
Message& push(const Repeating_group& t) {
v.push_back(t.field1);
v.push_back(t.field2);
return v;
}
// etc.
};
int main(){
Message v;
v.push8(0x32).push8(8);
for (...) {
v.push(Repeating_group(i, i * 10));
}
}
我正在使用 union 来填充 char 类型消息缓冲区中的一些消息字段。如果消息的长度不变,它就可以正常工作。请参阅下面的简化代码示例。
问题是,我的消息可以有可变长度。具体来说,const N
将在运行时决定。有没有办法通过为 buf
?
我正在探索智能指针,但到目前为止还没有成功。
const int N = 4;
struct repeating_group_t {
uint8_t field1;
uint8_t field2;
}rpt_group;
struct message_t
{
union
{
char buf[2 + 2*N];
struct {
uint8_t header;
uint8_t block_len;
std::array<repeating_group_t, N> group;
};
};
};
int main()
{
message_t msg;
msg.header = 0x32;
msg.block_len = 8;
for (auto i = 0; i < N; i++)
{
msg.group[i].field1 = i;
msg.group[i].field2 = 10*i;
}
// msg.buf is correctly filled
return 0;
}
您不能在运行时计算 N,因为 c 数组(您的 buf
)和 std::array
在其类型中都有大小信息。
此外 - 使用 union 进行(反)序列化不是一个好习惯 - 你的结构的大小将取决于它被编译的给定机器上所需的对齐等等...你可以添加 packed
属性来克服它,但你仍然有很多平台依赖性问题。
关于可变长度 - 您需要编写自定义(反)序列化程序来理解和 store/read 该大小信息以在另一端重新创建该容器。
您想将这些消息传递到哪里?
如评论所说,使用std::vector
。
int main() {
// before C++17 use char
std::vector<std::byte> v.
v.push_back(0x32);
v.push_back(8);
for (auto i = 0; i < N; i++) {
v.push_back(i);
const uint16_t a = 10 * i;
// store uint16_t in big endian
v.push_back(a >> 16);
v.push_back(a & 0xff);
}
}
对于自定义数据类型,您可以提供自己的流式或容器式容器和重载 operator>>
或您为数据类型选择的其他自定义函数。
struct Message{
std::vector<std::byte> v;
Message& push8(uint8_t t) { ... }
// push 16 bits little endian
Message& push16le(uint16_t t) { ... }
// push 16 bits big endian
Message& push16be(uint16_t t) { ... }
// etc
Message& push(const Repeating_group& t) {
v.push_back(t.field1);
v.push_back(t.field2);
return v;
}
// etc.
};
int main(){
Message v;
v.push8(0x32).push8(8);
for (...) {
v.push(Repeating_group(i, i * 10));
}
}