仅设置符号位的二进制补码整数应当是陷阱表示
把最低的二进制补码整数值(仅符号位为 1 的模式,例如 `INT_MIN`)当作陷阱或类似 NaN 的哨兵,可能会让整数溢出和可选整数更安全、更容易处理,但这会破坏现有代码,并且需要硬件或编译器支持。评论者在对称范围和内建“缺失”值的吸引力,与性能、FFI 互操作性,以及几十年来假设简单回绕算术的软件现实之间进行权衡。许多人认为,更好的工具(sanitizer、显式大整数,或带保留“niche”值的新整数类型)比在 C、C++ 和常见 ISA 中重新定义核心整数语义更可取。
提议与动机
- 讨论的核心是把“全符号位”的二进制补码值(例如
INT_MIN)设为特殊情况:- 要么作为陷阱表示(使用它会导致故障/异常)。
- 要么作为类似 NaN 的哨兵值,用于表示“缺失”/无效整数。
- 讨论到的动机:
- 对称的整数范围(−N..+N,而不是 −N−1..+N)。
- 使用这种位模式来更便宜地表示
optional<int>/ 可空整数。 - 消除 C 中像
abs(INT_MIN)溢出这样的边角情况。
硬件、性能与实现
- 许多人认为这只有在硬件支持下才真正有意义;在每次操作后都由软件检查被认为对低级语言来说代价过高。
- 也有人指出,动态语言或高级语言(Python、Lisp、Swift、R)本来就已经在承担类似成本(大整数、边界检查、哨兵值)。
- DSP 和某些 ISA 支持替代的算术模式(饱和算术、溢出标志),也可以加以利用。
正确性、UB 与语言语义
- 围绕 C/C++ 有符号溢出是未定义行为展开了激烈争论:
- 有些人希望把回绕(
-fwrapv)或陷阱(-ftrapv)作为默认行为。 - 也有人强调,依赖 UB 做优化已经造成了真实的安全漏洞和难以调试的行为。
- 有些人希望把回绕(
- 区分了两种概念:
- 陷阱 表示(在 C 中,仅仅读取/写入它就是 UB)。
- 类似 NaN 的值,具有定义明确的传播语义。
- 有几条评论指出,把这种机制改造进 C 会破坏现有、当前正确的代码以及 FFI 预期。
替代方案:大整数、饱和、哨兵
- 讨论的替代方案包括:
- 默认使用任意精度整数(Lisp、Scheme、Python)。
- 范围/区间类型,用越界值编码为“缺失”。
- 饱和算术指令或库操作。
- 语言或库层面的特定类型(非零、63 位整数、Rust 的 “niche” 优化、OCaml 的带标签整数、R 的 NA 整数)。
安全性 vs 可用性
- 有些人更倾向于在溢出时崩溃/触发陷阱,以避免静默的数据损坏。
- 另一些人,尤其是在安全关键或任务关键领域,更优先在值错误时继续运行,而不是让进程死亡。
- 结论是:理想行为高度依赖具体领域;单一的硬件或语言默认设置无法满足所有使用场景。