You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C23之前如何在块作用域用复合字面量指针初始化静态常量结构体?

C23前块作用域中静态const结构体的指针初始化问题

以下代码会被GCC和Clang拒绝:

struct thing;

typedef enum {
  THING_TYPE_A,
  THING_TYPE_B,
} thing_type_t;

typedef struct thing_a {
  int i;
} thing_a_t;

typedef struct thing_b {
  struct thing const *t;
} thing_b_t;

typedef struct thing {
  thing_type_t type;
  union {
    thing_a_t a;
    thing_b_t b;
  } t;
} thing_t;

thing_t const *get_thing(void) {
  static const thing_t s_thing = {
    .type = THING_TYPE_B, 
    .t = {
      .b = { 
        .t = &(thing_t) { .type = THING_TYPE_A, .t = { .a = { .i = 234 } } } 
      }
    },   
  };

  return &s_thing;
}

根据C标准中复合字面量的规则:

复合字面量所指代的无名对象,若在文件作用域则具有静态存储期,若在块作用域则具有自动存储期(此时对象生命周期随块结束而终止)。

这就是编译报错的核心原因:用来初始化s_thing.t.b.t的匿名thing_t是块作用域内的复合字面量,属于自动存储期,其地址并非编译时常量,无法用于静态变量的初始化。如果把s_thing移到文件作用域,编译器就会接受——因为此时复合字面量拥有静态存储期。

C23标准新增了在复合字面量括号内指定constexpr的特性,能直接解决这个问题,但在C23之前,我们能不能在块作用域中实现类似s_thing的声明:初始化一个包含指向另一常量变量指针的静态const结构体,同时无需显式将匿名thing_t声明为单独变量?

答案是不行,必须显式声明一个静态常量对象替代复合字面量,但可以通过将这个静态对象放在块作用域内,避免污染全局命名空间,代码依然保持紧凑:

thing_t const *get_thing(void) {
  // 块作用域内的静态常量对象,仅当前函数可见
  static const thing_t nested_thing = { 
    .type = THING_TYPE_A, 
    .t = { .a = { .i = 234 } } 
  };
  static const thing_t s_thing = {
    .type = THING_TYPE_B, 
    .t = {
      .b = { .t = &nested_thing }
    },   
  };

  return &s_thing;
}

这种方式既满足了块作用域的限制,又保证所有对象都是静态存储期,其地址可以合法作为静态变量的初始化器。

内容的提问来源于stack exchange,提问作者Charles Nicholson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 19:00:24