通过宏组合两个指定的初始化器

标签 c c99 designated-initializer

在一个嵌入式项目中,我使用了一个库,它提供了一个用于初始化结构的宏。这提供了合理的默认值,但默认值取决于其他参数。我想覆盖此指定初始化程序的一个或多个值,因为之后初始化这些值会产生开销。

理想情况下,我不想复制粘贴所有宏,因为这样我就必须管理第三方代码。如果库更改了它的默认值,我也不想这样做。

有没有办法合并或覆盖 designated initializers ,所以没有开销?代码必须符合 C99 标准且可移植。

演示问题的一些示例代码:

#if SITUATION
#define LIBRARY_DEFAULTS \
{ \
  .field_a = 1, \
  .field_b = 2, \
  .field_c = 3 \
}
#else
#define LIBRARY_DEFAULTS \
{ \
  .field_a = 100, \
  .field_b = 200, \
  .field_c = 300, \
  .field_d = 400, \
  .field_e = 500 \
}
#endif

/* The following is what I want (or similar), but (of course) doesn't 
   work. */
// #define MY_DEFAULTS = LIBRARY_DEFAULTS + { .field_a = 100 }

int main(void) {
    /* The exact definition of something also depends on situation. */
    struct something library_thing = LIBRARY_DEFAULTS;

    /* This generates overhead, and I want to avoid this. It is certain
       that the field exists. */
    library_thing.field_a = 100;
}

最佳答案

您可以将您的 library_thing 包装在外部结构中,并从外部结构的初始化程序中进行覆盖:

#include <stdio.h>

struct foo {
    int a,b,c;
};

#define FOO_DEFAULTS { .a = 1, .b = 2, .c = 3 }

int main() {
    struct {
        struct foo x;
    } baz = {
        .x = FOO_DEFAULTS,
        .x.a = 4,
    };

    printf("%d\n", baz.x.a); // prints 4
}

其实你甚至可以做到

.x = FOO_DEFAULTS,
.x = {.a = 4},

如果您确实需要“合并”两个初始化器。

这在 Clang (7.0.2) 上编译良好,但在 -Winitializer-overrides 下生成警告。检查生成的代码确认该结构已使用 4, 2, 3 初始化,因此此技巧没有额外的开销。

关于通过宏组合两个指定的初始化器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35527273/

相关文章:

ios - 指定初始化程序?

C++20:强制使用指定初始化器来模拟命名函数参数

python - 为什么 Python 扩展模块需要在 Windows 上用 MSVC 编译?

c - 有没有 libgpod 的 Linux 替代品来读取/写入 iPod 数据库?

c99 - 错误 : unknown type name ‘pid_t’

c - 为什么允许多次声明 typedef 标识符?

c - C99 fesetround()/fegetround() 状态是按线程还是按进程?

c - 一步一步的C编译导致segfault

c - 为什么 make 打印 "make: Nothing to be done for ` all'."?

c++ - 使用指定初始化程序时,我可以强制用户为成员提供值吗?