【问题标题】:Converting between const struct types in compile time在编译时在 const 结构类型之间进行转换
【发布时间】:2015-02-11 07:43:01
【问题描述】:

给定一个 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 }
};

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

【问题讨论】:

  • 您使用的是C99或更高版本吗?
  • 我使用 gcc 没有指定 -std=c99;尽管它看起来很像,但它也可以是一个 gnu 扩展......

标签: c struct unions compile-time


【解决方案1】:

此声明未声明变量。

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

【讨论】:

  • 是的,我会编辑问题,因为它包含复制粘贴错误。
【解决方案2】:

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

【讨论】:

  • 已经够漂亮了。鉴于第一句话为真,常量表达式中不能使用常量变量,那就是宏魔术时间。
【解决方案3】:

你不能在数组初始化器中传递除文字以外的任何东西。 请改用memcpy(3)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-09
    • 2014-11-28
    • 1970-01-01
    • 2021-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多