我该如何检测无符号整数溢出?

733

我正在使用C++编写程序,以找到所有满足ab=c的解,其中abc一起使用所有数字0-9,每个数字仅使用一次。该程序循环遍历ab的值,并每次在abab上运行数字计数例程,以检查是否满足数字条件。

然而,当ab超出整数限制时,会生成虚假的解。最终我使用类似以下代码来检查这种情况:

unsigned long b, c, c_test;
...
c_test=c*b;         // Possible overflow
if (c_test/b != c) {/* There has been an overflow*/}
else c=c_test;      // No overflow

有没有更好的方法来测试溢出?我知道一些芯片在溢出发生时会设置内部标志,但我从未在C或C++中看到它被访问过。


请注意,在C和C++中,带符号int溢出是未定义行为,因此您必须在不实际引起溢出的情况下进行检测。关于加法之前的带符号整数溢出,请参见Detecting signed overflow in C/C++


29
以下是关于这个主题可能有用的信息:Seacord的《C和C++安全编码》第5章 - http://www.informit.com/content/images/0321335724/samplechapter/seacord_ch05.pdf 用于C++的SafeInt类 - http://blogs.msdn.com/david_leblanc/archive/2008/09/30/safeint-3-on-codeplex.aspx - http://www.codeplex.com/SafeInt 用于C的IntSafe库:- [http://blogs.msdn.com/michael_howard/archiv - Michael Burr
3
Seacord的Secure Coding是一个很好的资源,但不要使用IntegerLib。请参阅http://blog.regehr.org/archives/593/。 - jww
44
使用gcc编译器选项-ftrapv将导致在(有符号)整数溢出时生成一个SIGABRT信号。详见此处 - nibot
3
它并没有回答溢出问题,但另一种解决方法是使用类似GMP的BigNum库来保证您始终具有足够的精度。如果您预先分配足够的数字,就不必担心溢出问题。 - wrdieter
1
@HeadGeek在他的回答中提供的信息基本上也是我会说的。但是,还有一个补充。你现在检测乘法溢出的方式可能是最快的。在ARM上,正如我在HeadGeek的回答中评论的那样,您可以使用clz指令或__clz(unsigned)函数来确定数字的等级(其最高位在哪里)。由于我不确定这是否适用于x86或x64,因此我假设它不可用,并且说找到最高有效位将需要最多log(sizeof(int)*8)条指令。 - nonsensickle
显示剩余2条评论
31个回答

313
我看到你正在使用无符号整数。根据定义,在C语言中(我不知道C++),无符号算术不会溢出...所以,至少对于C语言,你的观点是无意义的 :)
使用有符号整数时,一旦发生溢出,就会发生未定义行为(UB),你的程序可能会执行任何操作(例如:使测试结果不确定)。
#include <limits.h>

int a = <something>;
int x = <something>;
a += x;              /* UB */
if (a < 0) {         /* Unreliable test */
  /* ... */
}

为了创建符合要求的程序,您需要在产生溢出之前测试溢出。该方法也可以用于无符号整数:
// For addition
#include <limits.h>

int a = <something>;
int x = <something>;
if (x > 0 && a > INT_MAX - x) // `a + x` would overflow
if (x < 0 && a < INT_MIN - x) // `a + x` would underflow

// For subtraction
#include <limits.h>
int a = <something>;
int x = <something>;
if (x < 0 && a > INT_MAX + x) // `a - x` would overflow
if (x > 0 && a < INT_MIN + x) // `a - x` would underflow

// For multiplication
#include <limits.h>

int a = <something>;
int x = <something>;
// There may be a need to check for -1 for two's complement machines.
// If one number is -1 and another is INT_MIN, multiplying them we get abs(INT_MIN) which is 1 higher than INT_MAX
if (a == -1 && x == INT_MIN) // `a * x` can overflow
if (x == -1 && a == INT_MIN) // `a * x` (or `a / x`) can overflow
// general case
if (x != 0 && a > INT_MAX / x) // `a * x` would overflow
if (x != 0 && a < INT_MIN / x) // `a * x` would underflow

对于除了INT_MIN-1这两种特殊情况以外的除法,不可能超过INT_MININT_MAX


130
在C++中,无符号整数也不会严格溢出(ISO / IEC 14882:2003 3.9.1.4)。 我在问题中使用“溢出”的含义更加口语化,旨在包括无符号类型的明确定义的包装,因为我对无符号整数表示数学上的正整数感兴趣,而不是2^32(或2^64)模数下的正整数。 溢出作为从数学上无限大的整数行为偏离和作为语言中未定义行为的区别似乎很少被明确说明。 - Chris Johnson
18
这个测试不必是 x >= 0x > 0 就足够了(如果 x == 0,那么由于明显的原因 x + a 不会溢出)。 - caf
6
我喜欢这种方法...不过,要小心:乘法溢出检测假设x为正数。当x等于0时,会导致除以零检测,而对于负数的x,它总是错误地检测到溢出。 - Franz D.
5
如果 (a < INT_MIN / x) 的测试过于晚了。首先需要一项 if (x == -1) 的测试。 - chux - Reinstate Monica
4
@pmg,似乎“溢出”的“乘法”“一般情况”测试不正常工作。例如,取乘积15 * -6734,结果为-101010,但测试将表示它会溢出。 - dot_Sp0T
显示剩余8条评论

236

从 C23 开始,标准头文件 <stdckdint.h> 提供了以下三个类似函数的宏:

bool ckd_add(type1 *result, type2 a, type3 b);
bool ckd_sub(type1 *result, type2 a, type3 b);
bool ckd_mul(type1 *result, type2 a, type3 b);

其中type1type2type3都是整数类型。这些函数分别使用任意精度加、减或乘以a和b,并将结果存储在*result中。如果结果无法用type1表示,函数将返回true("计算溢出")。 (任意精度是一种虚幻的概念;计算非常快,自从20世纪90年代初可用的几乎所有硬件可以在一两个指令内完成。)

重新编写OP的示例:

unsigned long b, c, c_test;
// ...
if (ckd_mul(&c_test, c, b))
{
    // returned non-zero: there has been an overflow
}
else
{
    c = c_test; // returned 0: no overflow
}

c_test包含所有情况下乘法操作可能发生溢出的结果。

早在C23之前,GCC 5+ 和 Clang 3.8+ 提供了内置函数,它们的工作方式相同,但不同的是结果指针是最后传递而非第一个: __builtin_add_overflow, __builtin_sub_overflow__builtin_mul_overflow。这些函数也适用于小于int类型的数据。

unsigned long b, c, c_test;
// ...
if (__builtin_mul_overflow(c, b, &c_test))
{
    // returned non-zero: there has been an overflow
}
else
{
    c = c_test; // returned 0: no overflow
}

Clang 3.4+引入了带有固定类型的算术溢出内建函数,但它们的灵活性要少得多,而且Clang 3.8已经可用很长时间了。如果您需要使用这个较为方便的新替代方法之外的方法,请查找__builtin_umull_overflow

Visual Studio的cl.exe没有直接相应的功能。对于无符号加法和减法,包括<intrin.h>,您可以使用addcarry_uNNsubborrow_uNN(其中NN是位数,如addcarry_u8subborrow_u64)。它们的签名有点晦涩:

unsigned char _addcarry_u32(unsigned char c_in, unsigned int src1, unsigned int src2, unsigned int *sum);
unsigned char _subborrow_u32(unsigned char b_in, unsigned int src1, unsigned int src2, unsigned int *diff);
输入时,c_in/b_in是进位/借位标志,在输出时返回进位/借位。对于有符号操作或乘法,似乎没有相应的等价物。

另外,现在 Windows 版本的 Clang 已经可以投入生产(足够好用,适合 Chrome),所以这也是一个选择。


2
@RichardCook,花了一些时间,但是Clang在3.9版本中具有通用内建函数。 - zneak
5
根据文档__builtin_add_overflow和其它相关函数应该已经可用于Clang 3.8。 - Lekensteyn
3
谢谢。这很有效。你知道Visual C++的对应函数是什么吗?好像找不到它们。 - Mudit Jain
1
很棒的信息!请注意,除以有符号整数也可能会溢出(特别是 INT_MIN / -1,因为在通常的二进制补码表示中,abs(INT_MIN) == INT_MAX + 1),但似乎没有相应的内置函数。 - j_random_hacker
3
通过对微软采用更新的C标准的基本模式识别,我们可以预计C23功能将在2037年之前出现在Visual Studio中。 - Medinoc
显示剩余5条评论

173

通过使用操作数的最高有效位的位置和一些基本的二进制数学知识,有一种方法可以确定操作是否可能溢出。

对于加法,任何两个操作数将导致结果比最大操作数的最高有效位多一个位。例如:

bool addition_is_safe(uint32_t a, uint32_t b) {
    size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b);
    return (a_bits<32 && b_bits<32);
}

对于乘法,任何两个操作数的结果都将最多是这两个操作数的位数之和。例如:

bool multiplication_is_safe(uint32_t a, uint32_t b) {
    size_t a_bits=highestOneBitPosition(a), b_bits=highestOneBitPosition(b);
    return (a_bits+b_bits<=32);
}

同样地,你可以像这样估计ab次方结果的最大值:

bool exponentiation_is_safe(uint32_t a, uint32_t b) {
    size_t a_bits=highestOneBitPosition(a);
    return (a_bits*b<=32);
}

(当然,将目标整数的位数替换为实际位数。)

我不确定确定一个数中最高位是1的位置最快的方法是什么,这里有一种蛮力的方法:

size_t highestOneBitPosition(uint32_t a) {
    size_t bits=0;
    while (a!=0) {
        ++bits;
        a>>=1;
    };
    return bits;
}

虽然不完美,但这可以让你了解在进行操作之前是否会发生溢出。我不知道它是否比你建议的方式简单地检查结果更快,因为在 highestOneBitPosition 函数中有循环,但如果事先知道操作数中有多少位,它可能会更快。


111
当然,你可以将highestOneBitPosition重命名为log :) - Oliver Hallam
42
是的,这个操作和log2是相同的,但对于没有数学背景的人来说,这可能不太明显。 - Head Geek
48
这个算法难道不会低估安全答案吗?2^31 + 0 会被检测为不安全,因为 highestOneBitPosition(2^31) = 32。(2^32 - 1) * 1 会被检测为不安全,因为 32 + 1 > 32。1 ^ 100 会被检测为不安全,因为 1 * 100 > 32。 - clahey
20
根据你的multiplication_is_safe函数,0x8000 * 0x10000会溢出(位数为16+17=33,大于32),尽管实际上并没有溢出,因为0x8000 * 0x10000 = 0x80000000,显然仍适用于无符号32位整数。这只是该代码无法处理的许多示例之一。例如:0x8000 * 0x10001... - Michi
16
这几乎是没有用的。当它返回“安全”时,确实是这样的。否则,仍然需要执行完整的乘法运算,以确保它确实是安全的。考虑到可能出现错误否定报告的巨大值范围,当存在能够在不进行验证步骤的情况下返回正确答案的算法时,这种方法没有真正的价值。 - Brett Hale
显示剩余23条评论

58
一些编译器提供了访问 CPU 中整数溢出标志的功能,您可以进行测试,但这并不是标准的。
在执行乘法之前,您也可以测试是否可能会发生溢出:
if ( b > ULONG_MAX / a ) // a * b would overflow

11
使用numeric_limits<TYPE>::max()。 - Jonas Engström
24
不要忘记处理a=0的情况--此时除法运算会出错。 - Thelema
21
@Thelema说:“不要忘记处理a=0”,以及INT_MIN / -1。 - jww
1
如果 b == ULONG_MAX / a 呢?那么它仍然可以适合,只要 a 可以整除 ULONG_MAX - the swine
有趣的是,就性能而言,乘法比除法要快得多,而你却在每个乘法中添加了一个除法。这听起来不像是解决方案。 - jaques-sam

45

警告:使用-O2编译时,GCC可能会优化掉溢出检查。选项-Wall在某些情况下会给你一个警告,比如:

if (a + b < a) { /* Deal with overflow */ }

但不适用于这个例子:

b = abs(a);
if (b < 0) { /* Deal with overflow */ }

唯一安全的方法是在溢出发生之前检查,就像CERT文件中所述,但这将极为繁琐而难以系统化地使用。

使用-fwrapv编译可以解决问题,但会禁用一些优化。

我们迫切需要更好的解决方案。我认为编译器在进行依赖于不发生溢出的优化时,默认情况下应发出警告。目前的情况允许编译器优化掉溢出检查,我认为这是不可接受的。


11
请注意,编译器可能只对有符号整数类型执行此操作; 对于无符号整数类型,溢出完全被定义。 尽管如此,是的,这是一个非常危险的陷阱! - SamB
1
我认为编译器在进行依赖于溢出不发生的优化时,默认情况下应该发出警告。因此,for(int k = 0; k < 5; k++) {...} 应该会引发一个警告吗? - user253751
3
为什么需要呢?k 的值可以在编译时轻松确定,编译器不必做出任何假设。 - MikeMB
2
@immibis:引用上面的话:“我认为编译器在进行依赖于溢出不发生的优化时,默认情况下应该发出警告。” - MikeMB
1
@MikeMB 编译器优化中的问题是,在发出仅使用n的低5位的移位指令之前,编译器不会检查n是否小于32。 - user253751
显示剩余6条评论

37

Clang现在支持带符号和无符号整型的动态溢出检查。请参见-fsanitize=integer开关。目前,它是唯一支持完全的调试目的动态溢出检查的C++编译器。


28

这是一种非常快速的检测加法溢出的方法,可能会为乘法、除法和幂提供线索。

这个想法是由于处理器会让值回环到零,并且C/C++与任何特定的处理器都太抽象,因此您可以:

uint32_t x, y;
uint32_t value = x + y;
bool overflow = value < (x | y);

这样做可以确保如果一个操作数为零,而另一个不是,那么不会错误地检测到溢出,并且比之前建议的许多NOT/XOR/AND/test操作快得多。

正如所指出的那样,尽管这种方法比其他更为复杂的方式要好,但仍然可以进行优化。以下是包含优化的原始代码修订版本:

uint32_t x, y;
uint32_t value = x + y;
const bool overflow = value < x; // Alternatively "value < y" should also work

检测乘法溢出更高效、成本更低的方法是:

uint32_t x, y;
const uint32_t a = (x >> 16U) * (y & 0xFFFFU);
const uint32_t b = (x & 0xFFFFU) * (y >> 16U);
const bool overflow = ((x >> 16U) * (y >> 16U)) +
    (a >> 16U) + (b >> 16U);
uint32_t value = overflow ? UINT32_MAX : x * y;

这会导致在溢出时返回UINT32_MAX,或者返回乘法的结果。 在此情况下允许有符号整数进行乘法运算是严格未定义的行为。

值得注意的是,这使用部分Karatsuba方法乘法分解来计算64位乘法的高32位,以检查它们中是否有任何一个应该被设置为知道32位乘法溢出。

如果使用C ++,您可以将其转换为一个小而简洁的lambda表达式来计算溢出,以隐藏掉检测器的内部工作:

uint32_t x, y;
const bool overflow
{
    [](const uint32_t x, const uint32_t y) noexcept -> bool
    {
        const uint32_t a{(x >> 16U) * uint16_t(y)};
        const uint32_t b{uint16_t(x) * (y >> 16U)};
        return ((x >> 16U) * (y >> 16U)) + (a >> 16U) + (b >> 16U);
    }(x, y)
};
uint32_t value{overflow ? UINT32_MAX : x * y};

4
如果发生溢出,则 x+y>=256value=x+y-256。由于 y<256 总是成立,因此 (y-256) 为负数,因此 value < x 总是成立的。非溢出情况的证明也是相似的。 - Gunther Piez
2
@DX-MON:如果您之前有进位(carry)的话,第一个方法是必要的。uint32_t x[N], y[N], z[N], carry=0; for (int i = 0; i < N; i++) { z[i] = x[i] + y[i] + carry; carry = z[i] < (x[i] | y[i]); } 如果您不使用or运算符来计算值,就不能区分其中一个操作数和进位位为零以及一个操作数为 0xffffffff 而进位位为 1 的情况。 - Matt
你说得很好,@Matt,在求和/累加的情况下。很好地捕捉到了。 - DX-MON
1
@Matt,当x[i]y[i]都是0xFFFFFFFF且carry为1时,这种方法会失败。在加上进位之前,您必须先测试是否溢出,而此时您可能会放弃使用| - yuri kilochek
@yurikilochek,你说得很对。我已经很久没有考虑过这个问题了,但我不确定我是如何错过它的。 - Matt
显示剩余6条评论

28

我看到很多人回答了关于溢出的问题,但我想解决他的原始问题。他说问题是要找到一个b=c的a,使得所有数字都不重复。好吧,在这篇文章中他没有问这个,但我仍然认为有必要研究问题的上限并得出结论,他永远不需要计算或检测溢出(注意:我不精通数学,所以我一步一步地做了这一步,但最终结果非常简单,可能有一个简单的公式)。

主要问题在于问题要求a、b或c的上限为98,765,432。无论如何,从将问题分为简单和非简单两部分开始:

  • x0 == 1 (9、8、7、6、5、4、3、2的所有排列都是解决方案)
  • x1 == x (没有解决方案)
  • 0b == 0 (没有解决方案)
  • 1b == 1 (没有解决方案)
  • ab, a > 1, b > 1 (非简单)

现在我们只需要展示没有其他解决方案是可行的,只有排列是有效的(然后打印它们的代码是简单的)。我们回到上限。实际上,该问题的上限为c ≤ 98,765,432。这是上限,因为它是具有8位数字(总共10个数字减去每个a和b的1)的最大数字。这个上限仅适用于c,因为由于指数增长,a和b的范围必须要低得多,我们可以计算出,在将b从2变化到上限的情况下:

    9938.08^2 == 98765432
    462.241^3 == 98765432
    99.6899^4 == 98765432
    39.7119^5 == 98765432
    21.4998^6 == 98765432
    13.8703^7 == 98765432
    9.98448^8 == 98765432
    7.73196^9 == 98765432
    6.30174^10 == 98765432
    5.33068^11 == 98765432
    4.63679^12 == 98765432
    4.12069^13 == 98765432
    3.72429^14 == 98765432
    3.41172^15 == 98765432
    3.15982^16 == 98765432
    2.95305^17 == 98765432
    2.78064^18 == 98765432
    2.63493^19 == 98765432
    2.51033^20 == 98765432
    2.40268^21 == 98765432
    2.30883^22 == 98765432
    2.22634^23 == 98765432
    2.15332^24 == 98765432
    2.08826^25 == 98765432
    2.02995^26 == 98765432
    1.97741^27 == 98765432
例如,注意最后一行:它说1.97^27约等于98M。例如,1^27 == 1而2^27 == 134,217,728,这不是一个解决方案,因为它有9个数字(2 > 1.97所以它实际上比应该被测试的更大)。正如可以看到的那样,用于测试a和b的可用组合非常少。对于b == 14,我们需要尝试2和3。对于b == 3,我们从2开始,直到停止在462。所有结果都保证小于~98M。
现在只需测试上述所有组合,并寻找其中不重复任何数字的组合。
    ['0', '2', '4', '5', '6', '7', '8'] 84^2 = 7056
    ['1', '2', '3', '4', '5', '8', '9'] 59^2 = 3481
    ['0', '1', '2', '3', '4', '5', '8', '9'] 59^2 = 3481 (+leading zero)
    ['1', '2', '3', '5', '8'] 8^3 = 512
    ['0', '1', '2', '3', '5', '8'] 8^3 = 512 (+leading zero)
    ['1', '2', '4', '6'] 4^2 = 16
    ['0', '1', '2', '4', '6'] 4^2 = 16 (+leading zero)
    ['1', '2', '4', '6'] 2^4 = 16
    ['0', '1', '2', '4', '6'] 2^4 = 16 (+leading zero)
    ['1', '2', '8', '9'] 9^2 = 81
    ['0', '1', '2', '8', '9'] 9^2 = 81 (+leading zero)
    ['1', '3', '4', '8'] 3^4 = 81
    ['0', '1', '3', '4', '8'] 3^4 = 81 (+leading zero)
    ['2', '3', '6', '7', '9'] 3^6 = 729
    ['0', '2', '3', '6', '7', '9'] 3^6 = 729 (+leading zero)
    ['2', '3', '8'] 2^3 = 8
    ['0', '2', '3', '8'] 2^3 = 8 (+leading zero)
    ['2', '3', '9'] 3^2 = 9
    ['0', '2', '3', '9'] 3^2 = 9 (+leading zero)
    ['2', '4', '6', '8'] 8^2 = 64
    ['0', '2', '4', '6', '8'] 8^2 = 64 (+leading zero)
    ['2', '4', '7', '9'] 7^2 = 49
    ['0', '2', '4', '7', '9'] 7^2 = 49 (+leading zero)

没有一个匹配问题(这也可以从缺少“0”、“1”、…、“9”中看出)。

以下是解决它的示例代码。请注意,它是用Python编写的,不是因为它需要任意精度整数(代码不计算比9800万更大的任何内容),而是因为我们发现测试量太小,应该使用高级别语言来利用其内置容器和库(另请注意:该代码有28行)。

    import math

    m = 98765432
    l = []
    for i in xrange(2, 98765432):
        inv = 1.0/i
        r = m**inv
        if (r < 2.0): break
        top = int(math.floor(r))
        assert(top <= m)

        for j in xrange(2, top+1):
            s = str(i) + str(j) + str(j**i)
            l.append((sorted(s), i, j, j**i))
            assert(j**i <= m)

    l.sort()
    for s, i, j, ji in l:
        assert(ji <= m)
        ss = sorted(set(s))
        if s == ss:
            print '%s %d^%d = %d' % (s, i, j, ji)

        # Try with non significant zero somewhere
        s = ['0'] + s
        ss = sorted(set(s))
        if s == ss:
            print '%s %d^%d = %d (+leading zero)' % (s, i, j, ji)

1
为什么您不使用9.876.543.210作为上限? - Tom Roggero
3
因为等式左侧必须使用两位数字。 - hdante
2
虽然这并没有什么区别,但是上限实际上可以被视为 98765410,因为您已经声明了 LHS 上的值 > 1。 - Paul Childs

25

这是一个与平台不兼容的解决方案。英特尔x86和x64 CPU有所谓的EFLAGS寄存器,在每次整数算术运算后由处理器填充。这里我将跳过详细描述。相关标志是“溢出”标志(掩码0x800)和“进位”标志(掩码0x1)。为了正确解释它们,应考虑操作数是有符号还是无符号类型。

以下是从C/C++中检查标志的实用方法。以下代码适用于Visual Studio 2005或更新版本(32位和64位),以及GNU C/C++ 64位。

#include <cstddef>
#if defined( _MSC_VER )
#include <intrin.h>
#endif

inline size_t query_intel_x86_eflags(const size_t query_bit_mask)
{
    #if defined( _MSC_VER )

        return __readeflags() & query_bit_mask;

    #elif defined( __GNUC__ )
        // This code will work only on 64-bit GNU-C machines.
        // Tested and does NOT work with Intel C++ 10.1!
        size_t eflags;
        __asm__ __volatile__(
            "pushfq \n\t"
            "pop %%rax\n\t"
            "movq %%rax, %0\n\t"
            :"=r"(eflags)
            :
            :"%rax"
            );
        return eflags & query_bit_mask;

    #else

        #pragma message("No inline assembly will work with this compiler!")
            return 0;
    #endif
}

int main(int argc, char **argv)
{
    int x = 1000000000;
    int y = 20000;
    int z = x * y;
    int f = query_intel_x86_eflags(0x801);
    printf("%X\n", f);
}

如果操作数在没有溢出的情况下相乘,则从query_intel_eflags(0x801)中获得一个返回值为0,即既没有进位标志也没有溢出标志。在main()提供的示例代码中,发生了溢出,并且两个标志都设置为1。这个检查不意味着任何进一步的计算,因此应该非常快速。

1
这不会引起未定义行为吗?有符号溢出是未定义的行为。如果我错了,请纠正我,但即使您不使用结果,您也会得到UB。https://dev59.com/WWQo5IYBdhLWcg3wR9nD - PersonWithName
如果你想避免未定义行为,你可能也需要在汇编中进行乘法运算。 - PersonWithName

23
如果你有一个比你想要测试的数据类型更大的数据类型(比如你进行了32位加法,但是你有一个64位的类型),那么这将检测是否发生了溢出。我的例子是针对8位加法的,但它可以扩展到其他规模。
uint8_t x, y;    /* Give these values */
const uint16_t data16    = x + y;
const bool carry        = (data16 > 0xFF);
const bool overflow     = ((~(x ^ y)) & (x ^ data16) & 0x80);

这是基于该页面上解释的概念:https://www.cs.umd.edu/~meesh/cmsc311/clin-cmsc311/Lectures/lecture22/overflow.pdfhttps://web.archive.org/web/20170121033813/http://www.cs.umd.edu:80/class/spring2003/cmsc311/Notes/Comb/overflow.html wayback machine)
对于一个32位的示例,0xFF变为0xFFFFFFFF0x80变为0x80000000,最后uint16_t变为uint64_t

注意:这会捕获整数加法/减法溢出,我意识到你的问题涉及乘法。在这种情况下,除法可能是最好的方法。这通常是 calloc 实现确保参数不会溢出,因为它们相乘来获取最终大小的一种方式。


3
链接已损坏:HTTP 403:禁止访问 - Peter Mortensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接