I must send some data over a network where the package parts are not byte aligned. All packages are 8 byte long and an example package type might look like this:
union Packed
{
struct
{
uint64_t a : 5;
uint64_t b : 10;
bool c : 1;
};
uint64_t raw;
};
So the first 5 bits are field a
the next 10 bits are field b
and the last bit is field c
. Now I need a send
function that can send this and possibly other package types. The function should accept the fields as parameters. The low-level send function accepts a single uint64_t
.
My requirements are:
- An overflow should be detected at compile time
- The syntax should not be too bulky (subjective, but i will show what i want)
My first attempt
void send_struct(const Packed& packed)
{
raw_send(packed.raw);
}
int main()
{
send_struct({1000, 2, true}); // conversion changes value
Packed packed = {1000, 2, true}; // conversion changes value
send_struct(packed);
}
The warnings are generated which satisfies my first requirement, but i don't like the syntax: The curly braces look superfluous and manually creating a struct first is cumbersome.
With some warnings enable i even have to use two layers of curly braces, because the struct is nested inside the union.
Second attempt
template <typename ...Args>
void send_var(Args... args)
{
Packed packed {args...};
raw_send(packed.raw);
};
int main()
{
send_var(1000u, 2u, true);
}
Here, i like the syntax, but no warnings are generated, presumably because the bit width is lost somewhere.
Third attempt
struct A
{
uint64_t data : 5;
};
struct B
{
uint64_t data : 10;
};
void send_separate(A a, B b, bool c)
{
Packed packed {a.data, b.data, c};
raw_send(packed.raw);
}
int main()
{
send_separate({1000u}, {2u}, true); // conversion changes value
send_separate(1000u, 2u, true); // compile error
}
The first usage is ugly again: too many curly braces and the second one does not compile, because the structs cannot be implicitly constructed with a single value.
Question
How can i implement a function (and Package definition) such that the following function call compiles and shows a warning, because the value 1000
does not fit into 5 bit.
send(1000u, 2u, true);
I actually only care about the call site. The function and union definitions may be more complicated.
Using variables for the function parameters must work, too, of course
uint64_t a, b;
send(a, b, true); // should generate a warning
send(a & 0x1f, b & 0x3ff, true); // no warnings
The software will be used on linux only, is compiled with gcc
or clang
using at lease these warnings: -Wall -Wextra -pedantic
plus the flag that allows anonymous structs and unions.
Aucun commentaire:
Enregistrer un commentaire