
演讲嘉宾吴咏炜奇点智能研究院首席技术咨询师《C 实战核心技术与最佳实践》作者演讲主题契约式编程——C26 契约及其他大会2026 C 及系统软件技术大会 · 北京一、引言迟到四十年的原生契约“契约式设计”Design by ContractDbC的概念由 Bertrand Meyer 在 1980 年代提出至今已有四十余年。它的思想朴素而深刻一段代码的调用者与被调用者之间存在一份隐含的契约——调用者保证前置条件成立被调用者保证后置条件成立。然而直到C26这门诞生于 1985 年的语言才首次获得对契约的原生语言支持。吴咏炜作为国内知名 C 专家、《C 实战》作者将在这届大会深入剖析这一多年来最具争议的 C 语言特性。二、Design by Contract 的核心思想DbC 的三大支柱是前置条件precondition、后置条件postcondition、不变量invariant。契约类型语义责任方违反时意味着前置条件进入函数前必须为真调用者调用方的 bug后置条件函数返回后必须为真被调用者实现方的 bug不变量对象生命周期内恒为真双方状态被破坏一个经典的除法例子可以清晰呈现契约的价值// 未使用契约问题潜伏在运行时深处intsafe_divide(intdividend,intdivisor){if(divisor0){throwstd::invalid_argument(divisor must not be zero);}returndividend/divisor;}// 使用 C26 契约把约束显式化到接口intdivide(intdividend,intdivisor)[[pre:divisor!0]][[post r:r*divisordividend]]{returndividend/divisor;}契约与传统防御式检查的本质区别在于契约写的是接口的承诺而不是实现的补救。它把谁该为这个错误负责这个问题从运行时追溯变成了编译期可读的文档。三、C26 契约的语法与语义C26 契约引入了几种核心语法形式。3.1 前置与后置条件#includecontractvoidpush_back(constTvalue)[[pre:size()capacity()]][[post:size()old_size1]]{// ...}后置条件可以绑定返回值如[[post r: ...]]也可以引用函数进入时的旧值old_size。3.2 契约断言voidprocess(intlevel){contract_assert(level0);// ...}contract_assert与经典的assert不同它属于契约体系可以被统一配置违反行为且不能被NDEBUG静默移除。3.3 契约违反的三种处理方式契约违反后怎么办是整个特性最激烈的争议焦点。C26 最终提供了三种可配置的语义契约违反语义violation handling ├─ ignore 忽略违反继续执行发布模式常见 ├─ throw 抛出异常便于测试捕获 └─ eval_and_abort求值并终止最严格防御越界语义适用场景风险ignore生产环境、性能敏感契约形同虚设throw测试、可恢复场景可能掩盖早期错误eval_and_abort安全攸关、防御攻击进程直接终止争议的核心在于“契约违反是否应允许继续执行”。支持者认为契约的本质是文档化假设违反契约是编程错误任何继续执行都不可信反对者则认为在大型存量系统中激进终止会导致线上事故需要温和降级。四、争议为什么这是最受争议的特性吴咏炜在议题中特别强调了这个特性的争议性其历史确实充满反复语法之争从pre(...)函数体语法到[[pre: ...]]属性语法标准委员会反复横跳属性语法的采纳曾被视为对属性不影响语义原则的打破违反行为之争continue继续语义因安全问题被移除eval_and_abort与throw的取舍长期悬而未决ABI 与 ODR 影响契约是否参与函数签名、是否影响重载涉及海量存量代码的兼容性与 assert 的关系契约是否会取代传统assert抑或并存社区意见分裂这些争议并非学术清谈每一项都直接关系到数以亿计的存量 C 代码的演化路径。五、工程实践如何真正用好契约抛开语法细节吴咏炜强调的核心是契约改变的是代码的设计方式而非检查方式。5.1 在接口处写契约而非实现处好的契约写在公共接口上让调用者无需阅读实现即可理解约束糟糕的契约散布在实现深处等同于变形的断言。5.2 用契约表达不可能而非异常契约适合表达如果这里为假说明代码逻辑本身有 bug这类编程错误而资源耗尽、网络失败等运行期异常仍应使用异常机制。// 正确契约表达调用者必须先初始化voidconnect(Channelch)[[pre:ch.is_ready()]];// 错误把可预期的运行期失败塞进契约voidsend(Channelch,constPacketp)[[pre:!ch.is_full()]];// 网络拥塞是常态不应终止进程5.3 渐进式引入对存量项目可以从最关键的公共接口开始引入前置条件配合throw语义在测试环境运行逐步暴露历史遗留的调用错误再平滑过渡到更严格的语义。六、契约与测试、静态分析的协同契约并非孤立存在它与单元测试、静态分析共同构成三重防线。手段检查时机检查对象与契约的关系契约运行时可配置接口约束表达应然单元测试测试阶段行为正确性验证实然静态分析编译/CI 阶段潜在缺陷提前发现三者的分工清晰契约表达接口的应然约束单元测试验证具体行为静态分析在运行前拦截潜在缺陷。// 契约 静态分析的配合示例intindex_of(conststd::vectorintv,inttarget)[[pre:!v.empty()]][[post r:r-1||v[r]target]]{for(inti0;istatic_castint(v.size());i)if(v[i]target)returni;return-1;}前置条件!v.empty()让调用者必须保证容器非空后置条件则约束了返回值的语义。配合 clang-tidy 等静态分析工具对调用前未检查空容器的告警可以在 CI 阶段就把多数契约违反拦截在提交之前。吴咏炜强调契约的最终价值是让这些约束从人的记忆里、从散落的注释里沉淀为编译器可读、可执行、可审计的代码。七、总结四十年前提出的 Design by Contract终于以契约Contracts的形式原生进入 C26。它的价值不在于多了一种断言而在于把接口约束从隐式约定提升为显式契约让更健壮的代码从口号变成可执行的设计准则。2026 年 C 及系统软件技术大会上吴咏炜将以三十年系统级开发经验为开发者拆解这一最具争议特性的来龙去脉与落地之道。大会信息2026 奇点智能技术大会 C 及系统软件技术大会时间2026 年 11 月 20-21 日地点中国·北京万达文华酒店参会报名https://boolan.com/enroll/c1051/event/1162?channelseo立即报名与 C 实战专家面对面交流