Reputation: 20037
Given a constant struct in one API, which is to be interpreted as 16 consecutive uint8_t bytes in other API, is there a method in C to make this conversion in compile time:
What I'd like to achieve is something like
const union {
struct a {
uint32_t a;
uint16_t b;
uint16_t c;
uint8_t d[8];
} a;
uint8_t b[16];
} foo = { .a = { 0x12341243, 0x9898, 0x4554,
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 } } };
struct from_other_api manifest = {
.appuuid = foo.b;
// { foo.b[0], foo.b[1], ... }
};
This approach, as well the second version in the commented line unfortunately give both an error error: initializer element is not constant, even though this surely looks like a constant.
The business reason is that both the definitions struct from_other_api manifest
and the constant memory blob come an API, which is not to be modified. The conversion can be done manually as
struct from_other_api manifest = {
.appuuid = { 0x43, 0x12, 0x34, 0x12, 0x98, 0x98, 0x54, 0x45,
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }
};
but is to be avoided, as this is a regular pattern yelling to be automatized.
Upvotes: 1
Views: 127
Reputation: 16043
In C constant variables cannot be used in constant expressions.
If you can initialize manifest
at runtime, you can do it with memcpy
as in Snaipes answer.
But if manifest
must be initialized at compile time, you may need to (ab)use preprocessor. It won't be too pretty, but it works:
#define ID 0x12341243, 0x9898, 0x4554, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
#define FOO(nnn) { .a = FOO2(nnn) }
#define FOO2(a, b, c, d, e, f, g, h, i, j, k) \
{ a, b, c, { d, e, f, g, h, i, j, k } }
#define MAN(nnn) MAN2(nnn)
#define MAN2(a, b, c, d, e, f, g, h, i, j, k) \
{ a >> 0 & 0xFF, a >> 8 & 0xFF, a >> 16 & 0xFF, a >> 24 & 0xFF, \
b >> 0 & 0xFF, b >> 8 & 0xFF, \
c >> 0 & 0xFF, c >> 8 & 0xFF, \
d, e, f, g, h, i, j, k }
const union {
...
} foo = FOO(ID);
struct from_other_api manifest = {
.appuuid = MAN(ID)
};
Upvotes: 1
Reputation: 1221
You cannot pass anything other than literals in array initializers.
Use memcpy(3)
instead:
struct from_other_api manifest = {
// initialize other members
};
memcpy(manifest.appuuid, foo.b, sizeof (manifest.appuuid));
Upvotes: 1
Reputation: 3295
This declaration does not declare a variable.
struct a {
uint32_t a;
uint16_t b;
uint16_t c;
uint8_t d[8];
};
To declare a variable named a
with the same structure inside the union
, use this:
const union {
struct {
uint32_t a;
uint16_t b;
uint16_t c;
uint8_t d[8];
} a; // now a is accessible with a.a, a.b, a.c and a.d[i].
uint8_t b[16];
} foo = { .a = { 0x12341243, 0x9898, 0x4554,
{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 } } };
Upvotes: 2