Dangerous Unsigned Integer

Table of Contents

1. Modular Arithmetic

C 标准文档中有下面陈述(摘自 ISO&IEC-9899-1999(E) 6.2.5 Types):

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting type.

意思就是说 unsigned int 涉及的算术运算不是普通的加减乘除,而是 Modular Arithmetic

2. Uint 导致隐蔽的 Bug

下面我们看一个涉及 unsigned int 减法的代码:

 1: #include <stdio.h>
 2: 
 3: int main() {
 4:     unsigned int a = 1;
 5:     unsigned int b = 4;
 6: 
 7:     printf("%u - %u = %u\n", b, a, b-a);
 8:     printf("%u - %u = %u\n", a, b, a-b);
 9: 
10:     if ((a - b) < 0) {        // 你可能认为 1 - 4 小于 0,但这里的结果会令你意外
11:         printf("%u - %u < 0\n", a, b);
12:     } else {
13:         printf("%u - %u >= 0\n", a, b);
14:     }
15: 
16:     return 0;
17: }

执行上面代码,会输出:

4 - 1 = 3
1 - 4 = 4294967293
1 - 4 >= 0

是不是吓出一身冷汗,竟然执行到了上面程序的第 13 行(输出“1 - 4 >= 0”)。

再看一个涉及 unsigned int 乘法的代码:

 1: #include <stdio.h>
 2: 
 3: int main() {
 4:     unsigned int a = 5;
 5: 
 6:     printf("%u * 1 = %u\n", a, a * 1);
 7:     printf("%u * (-1) = %u\n", a, a * (-1));
 8: 
 9:     if (a * (-1) < 0) {    // 你可能认为 5 * (-1) 小于 0,但这里的结果会令你意外
10:         printf("%u * (-1) < 0\n", a);
11:     } else {
12:         printf("%u * (-1) >= 0\n", a);
13:     }
14: 
15:     return 0;
16: }

执行上面代码,会输出:

5 * 1 = 5
5 * (-1) = 4294967291
5 * (-1) >= 0

是不是吓出一身冷汗,竟然执行到了上面程序的第 12 行(输出“5 * (-1) >= 0”)。

unsigned int 采用 Modular Arithmetic 运算,可能无意间导致潜在的 Bug,别轻意用它。参考:https://www.learncpp.com/cpp-tutorial/unsigned-integers-and-why-to-avoid-them/

3. 其它语言处理 Uint

其它语言如何处理 Uint 的溢出问题呢?这需要参考其文档。

比如,Golang 中采用了和 C 中一样的方式,即采用 Modular Arithmetic 运算;而 Rust 语言中在 Debug 模式中会直接 panic,而在 Release 模式下,则不会 panic,而是采用 Modular Arithmetic 运算。参考:https://doc.rust-lang.org/book/ch03-02-data-types.html#integer-overflow

Author: cig01

Created: <2020-04-01 Wed>

Last updated: <2020-04-20 Mon>

Creator: Emacs 27.1 (Org mode 9.4)