在编译时在 const struct 类型之间转换

Converting between const struct types in compile time

给定一个 API 中的常量结构,在另一个 API 中将被解释为 16 个连续的 uint8_t 字节,C 中是否有一种方法可以在编译时间:

我想要实现的是

 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], ...  }
};

不幸的是,这种方法以及注释行中的第二个版本都给出了错误 error: initializer element is not constant,尽管这肯定 看起来 就像一个常数。

业务原因是定义 struct from_other_api manifest 和常量内存 blob 都来自 API,不能修改。转换可以手动完成

struct from_other_api manifest = {
    .appuuid = { 0x43, 0x12, 0x34, 0x12, 0x98, 0x98, 0x54, 0x45,
                 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }
};

但要避免,因为这是一种需要自动化的常规模式。

您不能在数组初始值设定项中传递文字以外的任何内容。 使用 memcpy(3) 代替:

struct from_other_api manifest = {
    // initialize other members
};
memcpy(manifest.appuuid, foo.b, sizeof (manifest.appuuid));

这个声明没有声明变量。

struct a {
     uint32_t a;
     uint16_t b;
     uint16_t c;
     uint8_t d[8];
 };

要在 union 中声明一个名为 a 且具有相同结构的变量,请使用:

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 } } };

在 C 中,常量变量不能用于常量表达式。

如果你可以在运行时初始化 manifest,你可以用 memcpy 来完成,就像 Snaipes 的回答一样。

但是如果manifest必须在编译时初始化,你可能需要(ab)使用预处理器。它不会太漂亮,但它有效:

#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)
};