在 C2y 中改进 _Generic

2024 年 8 月 1 日:

  • C23 后确定的前两次 C 会议结束,开始致力于 C2y。决定此周期不采用“先修复 bug 再发布”的方式,避免像 C11 到 C17 期间那样失去动力和活跃贡献者,此次同时处理 bug 修复和新特性。
  • 通用选择(Generic Selection)

    • _Generic是用于通用选择的关键字,C11 引入,通过传入表达式确定其类型并进行匹配,可插入表达式实现基于类型的行为,如:
    int f () {
      return 45;
    }
    
    int main () {
      const int a = 1;
      return _Generic(a,
          int: a + 2,
          default: f() + 4
      );
    }
    • 存在两个问题:

      • “l 值转换”问题:表达式进入_Generic表达式时会进行“l 值转换”,数组转为指针,修饰符被剥离,这有助于确定类型但会导致一些问题,如TYPE_MATCHES_EXPR宏在判断const类型时会失败,可通过typeof创建空指针表达式来解决,但这种方式较复杂。
      • 仅接受表达式:输入到类型通用宏的总是表达式,_Generic也仅接受表达式,这导致实现测试时需使用指针技巧,后来有人提出可以做得更好。
  • 推动改进:实现者抱怨无法直接匹配类型,Aaron Ballman 决定改进_Generic,将类型放入通常放表达式的位置,使其能直接匹配且无 l 值转换,如TYPE_MATCHES_EXPR可写为:

    #define TYPE_MATCHES_EXPR(DESIRED_TYPE,...) \
      _Generic(typeof((__VA_ARGS__)),\
          DESIRED_TYPE: 1,\
          default: 0\
      )

    Clang 几个月内实现,GCC 也在其主干中实现,该特性已正式进入 C2y,但其他编译器可能需要一些时间跟进,在某些场景下使用可能会引起混淆,如上述代码在使用类型匹配时不再匹配int,且暴露了一些关于表达式导致特定类型的问题,_Generic仍需一些改进。

  • 标签:[C]、[C 标准]、[_Generic]、[📜]
阅读 24
0 条评论