奇思妙想 · 2024年 4月 26日 0

数值溢出保护

90 次浏览

C/ObjC/C++在数值溢出时并未做过多保护,责任推给了程序员。

  • C/ObjC/C++选择相信程序员能控制溢出,不过有的编译器会提供溢出预防策略。
    char c = 128; // 假设char是有符号1字节
    - GCC/G++不会提示任何问题,gcc11.4即使用-Woverflow也不会有任何提示。
    - Clang会提示警告:implicit conversion from 'int' to 'char' changes value from 128 to -128
  • Go语言和C语言类似,选择相信程序员能控制溢出,发生溢出不会有任何错误。
  • Swift是设计安全的语言,编译期间发现数值存储不匹配,会直接报错,运行期发现溢出也会报错
    let a: UInt8 = -1
    同时,Swift也提供了溢出运算符(如&+&-&*等)来显式处理可能溢出的情况。
  • C#默认也不会对运行期溢出做处理,但可利用编译器选项/checked或者checked操作符/语句做全局、局部溢出检查,一旦发现溢出将抛出异常。
    • 代码或者编译选择指定checked,一定会有溢出检查;如果代码中指定unchecked, 会忽略编译选项/checked.
    • 注意,如果用常量赋值发生溢出,如short a = 32767,编译器会直接报错:常量值“32768”无法转换为“short”
  • Java和C#一样常量赋值逃不过编译器检查,默认也不会对运行期溢出做处理,运行期可利用特定API做溢出检查,比如加法检查Math.addExact方法。
    int a = Integer.MAX_VALUE;
    try {
        int result = Math.addExact(a, 1);
    } catch (ArithmeticException e) {
        System.out.println("Overflow exceptoin:" + e.getMessage());
    }
  • Python 3用long替代int, long几乎是无穷大(除非计算机内存无法存储long字符串),数值溢出很少出现在Python.
  • JS作为脚本语言,溢出是个很少考虑的话题。数值Number类型最大安全值MAX_SAFE_INTEGER超过万亿,如果不满足还可用更大的BigInt.
  • VB.NET之前编译阶段不会提示溢出,运行期溢出会报错。VB.NET编译期即可报错。
    - 例如:Dim bigNumber As Integer = Int32.MaxValue + 1
    报错:常量表达式无法在类型“Integer”中表示。
  • Rust作为一门安全放在首位的语言,编译期发现溢出会报错。
    let a: u32 = u32::MAX + 1; // 报错:arithmetic operation will overflow
    • 同时Rust提供一系列API反馈是否会溢出、溢出后是回绕还是设定最大/最小值。
      以加法为例,checked_add发生溢出返回None,overflowing_add返回溢出与否标志和计算值,saturating_add根据是上溢还是下溢设置为能表达的最大或最小值,wrapping_add会在发生溢出时回绕。
  • 仓颉 遇到溢出的字面量,一样会编译出错。
    var i: UInt8 = 300
    报错:the number '300' exceeds the value range of type 'UInt8'
  • PHP超出整数范围的数值会自动转换成浮点数以保证数值正确。