C 中的多态类型 [pdf]
一项通过 `_Type` 和 `_Var` 等新构造向 C 语言添加多态类型的提案,重新激起了长期存在的争论:C 应该在多大程度上继续演进,还是把相关需求交给 C++ 或更新的系统编程语言。支持者认为,类型安全的泛型、更好的数组支持以及运行时类型信息,将在嵌入式和航空等领域显著提升安全性、复用性和互操作性,尤其是在 C++ 编译器不可用或不可靠的场景中。批评者则反驳说,这种设计显得随意且语法丑陋,可能会用半吊子的方式让 C 变得臃肿,而不是干净地借鉴成熟理念,并可能削弱 C 作为小而可预测的核心语言的吸引力。
C 中多态类型的总体反响
- 许多人认为多态类型确实很有用,尤其适用于通用库,以及作为
void*模式更安全的替代方案。 - 该提案被视为“勇敢”的,但同时也显得“像补丁一样”,是勉强附加到 C 现有类型系统上的,而不是一个干净、第一等公民式的设计。
- 有人喜欢它的目标不仅限于 C++ 风格模板,而是指向更强大的多态/依赖类型,避免单态化和代码膨胀。
- 也有人批评其条件语义规则(“只在某些上下文中有效”)让人联想到 C++ 的复杂性,并使代码推理更困难。
C 与 C++ 及其他语言
- 一个反复出现的主题是:做泛型和多态时“直接用 C++” vs. “C++ 臃肿又混乱”。
- 一些人认为,C 应该只挑选 C++ 的“好部分”,并以更简单的形式呈现;另一些人则认为事情并非如此——这些新特性给人的感觉是半推半就,且比必要的更古怪。
- 有人明确从 C++ 回到了 C,理由是复杂性以及在真实代码库中对高级 C++ 特性的滥用。
- 讨论过的替代方案包括:Rust(被认为也在走向特性膨胀)、Ada(强大但难以推广)、带有
-betterC的 Zig/Odin/D,以及 C3(使用any*和“不要大理念”的哲学)。
类型安全、数组和 void*
- 关于 C++ 是否天生比 C 更类型安全,存在争论:
- 支持 C++ 的一方提到模板泛型、
std::array、更强的指针类型检查以及static_cast。 - 支持 C 的一方反驳说,现代 C 配合谨慎的风格(不让数组退化、尽量少做强制转换、用宏增强安全性)也能达到类似的安全性。
- 支持 C++ 的一方提到模板泛型、
- 多维数组:有人称赞 C 的 VLA 比 C++ 数组更好;也有人把它们称为安全风险,而反驳者则声称栈保护可缓解这一问题。
- 基于
void*的 API(例如qsort、PAM、Wayland)被视为痛点;类型安全的泛型被看作关键动机。
语法、关键字与美学
- 许多人强烈不喜欢
_Type/_Var/_Generic这类外观;很多人指出 C 代码库偏好全小写标识符。 - 解释是:以下划线加大写字母开头的形式是为了避免破坏现有代码而保留的;之后可能会出现小写别名或真正的关键字(就像 C23 里的
_Bool→bool一样)。 - 有人担心某些关键字(如
_Generic)从未获得更友好的别名,限制了采用;对_Type和_Var也有类似担忧。
用例与动态类型 / FFI
- 提议的好处包括:
- 类型安全的泛型接口(例如类似
qsort的函数)。 - 如果
_Typeof能提供可检查的运行时类型描述,那么在语言互操作方面,运行时构造类型和函数调用会更容易。
- 类型安全的泛型接口(例如类似
- 有些人质疑这些需求是否值得为了复杂化 C 而付出代价,认为应该改用别的语言;另一些人则认为,没有任何现有语言能同时匹配 C 的简洁性、可移植性和控制力。