I'm packing messages to be send to another device. I'm using C 11. Usually the payload is a single ASCII encoded value, but this one command has a bit more parameters. I'm trying to pack the payload in a single array of chars. I'm looking for a clean solution, and I thought that the following (example) solution should work:
Message foo(Parameters parameters) {
struct __attribute__((__packed__)) ParameterPayload {
std::array<char,2> a;
std::array<char,2> b;
std::array<char,2> c;
std::array<char,4> d;
}; // Actual struct has way more parameters
ParameterPayload paramPayload;
paramPayload.a = bar<2,10>(parameters.a);
paramPayload.b = bar<2,10>(parameters.b);
paramPayload.c = bar<2,10>(parameters.c);
paramPayload.d = bar<4,16>(parameters.d);
// This will not work, but I want something like this to work
auto payload = reinterpreted_cast<std::array<char, sizeof(ParameterPayload)>(paramPayload);
return baz<sizeof(ParameterPayload)>(payload);
}
template<size_t size, int base>
std::array<char, size> bar(int input> {
// ASCII encoding with a base (2, 10 or 16)
}
template<size_t payloadSize>
Message baz(std::array<char, payloadSize> payload) {
// Some packing computation
}
This is a rough example, but I think it will get the message across. How do I cast the struct to a single std:array<char, N>? Is it even possible? I'm trying not to do multiple std::copies instead, because that will cost more resources and will worsen readability.
another solution I looked into is using
const char* const payload = reinterpret_cast<const char* const>(¶mPayload);
and going from there... I could do a single copy after that, but I'd like to avoid it.
CodePudding user response:
That casting is pedantically UB (and even we don't have guaranty of exact size of std::array
).
I suggest to change to something like:
Message foo(Parameters parameters) {
std::array<char, 2 2 2 4> payload; // Actual struct has way more parameters
int offset = 0;
bar<2, 10>(parameters.a, payload.data() offset, offset);
bar<2, 10>(parameters.b, payload.data() offset, offset);
bar<2, 10>(parameters.c, payload.data() offset, offset);
bar<4, 16>(parameters.d, payload.data() offset, offset);
return baz(payload);
}
template<size_t size, int base>
void bar(int input, char* out, int& offset) /* std::span<char, size> out (in C 20) */
{
offset = size;
// ASCII encoding with a base (2, 10 or 16)
}
template<size_t payloadSize>
Message baz(std::array<char, payloadSize> payload) {
// Some packing computation
}