如何检测整数溢出?

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

但是,当b溢出整数限制时,可能会生成伪解。 我结束了检查这个使用代码,如:

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 

有没有更好的方法来testing溢出? 我知道一些芯片有一个内部的标志,当溢出发生时,但我从来没有见过它通过C或C ++访问。

有一种方法可以确定操作是否可能溢出,使用操作数中最重要的一位的位置和一些基本的二进制math知识。

另外,任何两个操作数都会导致(最多)比最大操作数的最高一位多一位。 例如:

 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); } 

类似的,你可以估计a的结果的最大值,就像这样:

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

(当然,用目标整数代替位数。)

我不知道确定数字中最高一位的最快方法,下面是一个暴力方法:

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

这并不完美,但是这样做会给你一个好主意,在做手术之前是否有两个数字可能会溢出。 我不知道这是否比按照您的build议方式检查结果快,因为在highestOneBitPosition函数中的循环,但是它可能(尤其是如果您知道操作数中有多less位预先)。

我看到你正在使用无符号整数。 根据定义, 在C (不知道C ++),无符号算术不溢出…所以,至less对于C,你的观点是没有意义的:)

使用带符号整数,一旦发生溢出,就会发生未定义行为 ,并且程序可以执行任何操作(例如:渲染testing不确定)。

 #include <limits.h> int a = <something>; int x = <something>; a += x; /* UB */ if (a < 0) { /* unreliable test */ /* ... */ } 

要创build一个合格的程序,您需要产生溢出之前testing溢出。 该方法也可以与无符号整数一起使用

 // 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>; if (a > INT_MAX / x) /* `a * x` would overflow */; if ((a < INT_MIN / x)) /* `a * x` would underflow */; // there may be need to check for -1 for two's complement machines if ((a == -1) && (x == INT_MIN)) /* `a * x` can overflow */ if ((x == -1) && (a == INT_MIN)) /* `a * x` (or `a / x`) can overflow */ 

除了INT_MIN-1特殊情况外,不可能超过INT_MININT_MAX

铿锵3.4+和GCC 5 +提供检查算术builtins 。 他们为这个问题提供了一个非常快速的解决scheme,特别是与比特testing安全检查相比。

对于OP的问题中的例子,它会这样工作:

 unsigned long b, c, c_test; if (__builtin_umull_overflow(b, c, &c_test)) { // returned non-zero: there has been an overflow } else { // return zero: there hasn't been an overflow } 

Clang文档没有指定如果发生溢出, c_test是否包含溢出的结果,但GCC文档说明了这一点。 鉴于这两个人喜欢与__builtin兼容,那么可以肯定的是,这也是Clang的工作原理。

每个算术运算都有一个__builtin ,对于int大小,long长度和long long长度,可以溢出(加法,减法,乘法),有符号和无符号variables。 这个名字的语法是__builtin_[us](operation)(l?l?)_overflow

  • u表示无符号s表示签名 ;
  • 操作是addsubmul ;
  • 没有后缀表示操作数是int ; 一个意味着long ; 两个意思long long

因此,对于一个有签名的长整数加法,它将是__builtin_saddl_overflow 。 完整列表可以在Clang文档页面find 。

GCC 5+和Clang 3.8+还提供通用的内build函数,不需要指定值的types:__builtin_add_overflow,__builtin_sub_overflow和__builtin_mul_overflow 。 这些也适用于小于inttypes。

内置版本降低到平台的最佳状态。 在x86上,他们检查进位,溢出和符号标志。

Visual Studio的cl.exe没有直接的等价物。 对于无符号的加法和减法,包括<intrin.h>将允许使用addcarry_uNNaddcarry_uNN (其中NN是位数,如addcarry_u8addcarry_u8 )。 他们的签名有些迟钝:

 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是input的进位/借位标志,返回值是进位/借位输出。 它似乎没有签名操作或乘法的等价物。

否则,铿锵的Windows也越来越好,所以这可能是一个选项。

一些编译器提供了访问CPU中的整数溢出标志,然后你可以testing,但这不是标准的。

在执行乘法之前,您还可以testing溢出的可能性:

 if ( b > ULONG_MAX / a ) // a * b would overflow 

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

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

但在这个例子中不是:

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

唯一安全的方法是在CERT文件中描述的溢出之前检查溢出,这将是系统地使用令人难以置信的繁琐。

-fwrapv编译解决了这个问题,但是禁用了一些优化。

我们迫切需要一个更好的解决scheme。 我认为编译器应该在默认情况下发出一个警告,当进行优化,而不会发生溢出。 目前的情况允许编译器优化溢出检查,这在我看来是不可接受的。

现在支持dynamic溢出检查有符号和无符号整数。 请参阅-fsanitize =整数切换。 目前,只有一个C ++编译器具有完全支持的用于debugging目的的dynamic溢出检查。

这是一个“不可移植”的解决scheme。 Intel x86和x64 CPU具有所谓的EFLAGS寄存器( http://en.wikipedia.org/wiki/EFLAGS ),每个整数算术运算后由处理器填充。 这里我将跳过一个详细的描述。 相关的标志是“溢出”标志(掩码0x800)和“进位”标志(掩码0x1)。 要正确解释它们,应该考虑操作数是有符号还是无符号types的。

这是从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.这个检查并不意味着进一步的计算,所以它应该是相当快的。

我看到很多人回答了溢出的问题,但我想解决他原来的问题。 他说问题是find一个b = c,这样所有的数字都可以不用重复使用。 好吧,这不是他在这篇文章中所要求的,但我仍然认为有必要研究问题的上限,并得出结论,他永远不需要计算或检测溢出(注意:我不熟练在math中,所以我一步一步做了这个,但最终的结果是如此简单,这可能有一个简单的公式)。

主要的一点是,问题对于a,b或c所要求的上限是98.765.432。 无论如何,从琐碎和不平凡的部分分开问题开始:

  • x 0 == 1(9,8,7,6,5,4,3,2的所有置换都是解)
  • x 1 == x(没有可能的解决scheme)
  • 0 b == 0(没有解决scheme)
  • 1 b == 1(没有解决scheme)
  • a b ,a> 1,b> 1(非平凡)

现在我们只需要certificate没有其他解决scheme是可能的,只有排列是有效的(然后打印它们的代码是微不足道的)。 我们回到上限。 其实上限是c≤98.765.432。 这是上限,因为它是最大的8位数字(总共10位数字,每个a和b都减1)。 这个上限仅适用于c,因为a和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,这不是一个解决scheme,因为它有9个数字(2> 1.97,所以它实际上比应该testing的大)。 可以看出,可用于testinga和b的组合是非常小的。 对于b == 14,我们需要尝试2和3.对于b == 3,我们从2开始,在462停止。所有的结果被授予小于〜98M。

现在只要testing上面的所有组合,并寻找那些不重复任何数字的组合:

  ['0', '2', '4', '5', '6', '7', '8'] 2^84 = 7056 ['1', '2', '3', '4', '5', '8', '9'] 2^59 = 3481 ['0', '1', '2', '3', '4', '5', '8', '9'] 2^59 = 3481 (+leading zero) ['1', '2', '3', '5', '8'] 3^8 = 512 ['0', '1', '2', '3', '5', '8'] 3^8 = 512 (+leading zero) ['1', '2', '4', '6'] 2^4 = 16 ['0', '1', '2', '4', '6'] 2^4 = 16 (+leading zero) ['1', '2', '4', '6'] 4^2 = 16 ['0', '1', '2', '4', '6'] 4^2 = 16 (+leading zero) ['1', '2', '8', '9'] 2^9 = 81 ['0', '1', '2', '8', '9'] 2^9 = 81 (+leading zero) ['1', '3', '4', '8'] 4^3 = 81 ['0', '1', '3', '4', '8'] 4^3 = 81 (+leading zero) ['2', '3', '6', '7', '9'] 6^3 = 729 ['0', '2', '3', '6', '7', '9'] 6^3 = 729 (+leading zero) ['2', '3', '8'] 3^2 = 8 ['0', '2', '3', '8'] 3^2 = 8 (+leading zero) ['2', '3', '9'] 2^3 = 9 ['0', '2', '3', '9'] 2^3 = 9 (+leading zero) ['2', '4', '6', '8'] 2^8 = 64 ['0', '2', '4', '6', '8'] 2^8 = 64 (+leading zero) ['2', '4', '7', '9'] 2^7 = 49 ['0', '2', '4', '7', '9'] 2^7 = 49 (+leading zero) 

没有一个符合这个问题(这也可以通过“0”,“1”,…,“9”的缺失来看到)。

解决它的示例代码如下。 还要注意,这是用python编写的,并不是因为它需要任意的精度整数(代码不会计算大于9800万的数据),而是因为我们发现testing的数量太小,所以我们应该使用高级语言利用其内置的容器和库(也注意:代码有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) 

如果你的数据types大于你想testing的数据types(比如你做了一个32位的添加,而你有一个64位的types)。 然后这将检测是否发生溢出。 我的例子是一个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); 

它基于这个页面上解释的概念: http : //www.cs.umd.edu/class/spring2003/cmsc311/Notes/Comb/overflow.html

对于一个32位的例子, 0xff变成0xffffffff0x80变成0x80000000 ,最后uint16_t变成uint64_t

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

最简单的方法是将你的unsigned long unsigned long long转换成unsigned long long ,做你的乘法运算,并把结果与0x100000000LL比较。

您可能会发现,比您在示例中完成的部门更高效。

哦,它将在C和C ++中都能正常工作(正如你用两个标签来标记问题一样)。


刚刚看了一下glibc手册 。 有一个整数溢出陷阱( FPE_INTOVF_TRAP )作为SIGFPE一部分。 除了手册中令人讨厌的部分之外,这将是理想的:

FPE_INTOVF_TRAP整数溢出(在C程序中是不可能的,除非您以硬件特定的方式启用溢出陷阱)。

有点耻辱真的。

对于无符号整数,只需检查结果是否小于其中一个参数:

 unsigned int r, a, b; r = a+b; if (r < a) { // overflow } 

对于有符号整数,您可以检查参数和结果的符号。 不同符号的整数不能溢出,只有同一符号的整数溢出的结果是不同的符号:

 signed int r, a, b, s; r = a+b; s = a>=0; if (s == (b>=0) && s != (r>=0)) { // overflow } 

您不能从C / C ++访问溢出标志。

一些编译器允许你在代码中插入陷阱指令。 在海湾合作委员会的选项是-ftrapv(但我不得不承认,我从来没有使用它,将张贴后检查)。

你可以做的唯一可移植和独立于编译器的东西是自己检查溢出。 就像你在你的例子中所做的一样。

编辑:

刚刚检查:-ftrapv似乎没有在x86上使用最新的GCC。 猜猜这是一个旧版本或其他架构特有的遗留问题。 我希望编译器在每次添加之后插入一个INTO操作码。 不幸的是,它不这样做。

虽然已经两年了,但是我觉得不妨加一个我的最低限度的方法来检测至less是多余的溢出,这可能会带来乘法,除法和权力

这个想法正是因为处理器会让值回到零,而C / C ++是从任何特定的处理器中抽象出来的,你可以:

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

这既保证了如果一个操作数为零而一个操作数不为零,那么溢出就不会被错误地检测出来,而且比以前提到的大量的NOT / XOR / AND /testing操作要快得多。

编辑 :正如指出的,这种方法虽然比其他更精细的方法更好,但仍然是可以优化的。 以下是包含优化的原始代码的修订:

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

我需要回答这个浮点数的相同的问题,其中位掩码和移位看起来并不乐观。 我解决的方法是用于有符号和无符号的整数和浮点数。 即使没有更大的数据types以促进中间计算,它也可以工作。 这并不是所有这些types中最有效率的,但是因为它对所有这些types都有效,所以值得使用。

签名溢出testing,加法和减法:

  1. 获取表示typesMAXVALUE和MINVALUE的最大和最小可能值的常量。

  2. 计算和比较操作数的符号。

    一个。 如果任一值为零,则加法和减法都不能溢出。 跳过剩余的testing。

    湾 如果符号相反,则加法不能溢出。 跳过剩余的testing。

    C。 如果符号相同,则减法不能溢出。 跳过剩余的testing。

  3. testingMAXVALUE的正溢出。

    一个。 如果两个符号均为正数,且MAXVALUE – A <B,则加法将溢出。

    湾 如果B的符号是负的,MAXVALUE – A <-B,则减法将溢出。

  4. testingMINVALUE的负溢出。

    一个。 如果两个符号均为负值,且MINVALUE – A> B,则加法将溢出。

    湾 如果A的符号是负数,MINVALUE – A> B,则减法将溢出。

  5. 否则,不会溢出。

签名溢出testing,乘法和除法:

  1. 获取表示typesMAXVALUE和MINVALUE的最大和最小可能值的常量。

  2. 计算并比较操作数的大小(绝对值)。 (下面,假设A和B是这些大小,而不是签名的原件。)

    一个。 如果任一值为零,则乘法不能溢出,并且除法将产生零或无穷大。

    湾 如果任一值为1,则乘法和除法不能溢出。

    C。 如果一个操作数的大小小于1,另一个大于1,则乘法不能溢出。

    d。 如果幅度都小于1,则划分不能溢出。

  3. testingMAXVALUE的正溢出。

    一个。 如果两个操作数都大于1且MAXVALUE / A <B,则乘法将溢出。

    湾 如果B小于1且MAXVALUE * B <A,则分频将溢出。

  4. 否则,不会溢出。

注意:MINVALUE的最小溢出由3处理,因为我们取绝对值。 但是,如果ABS(MINVALUE)> MAXVALUE,那么我们将会有一些罕见的误报。

下溢的testing是相似的,但涉及EPSILON(最小的正数大于零)。

另一个有趣的工具: http : //embed.cs.utah.edu/ioc/

这是一个修补的clang编译器,它在编译时将代码添加到代码中。 所以你得到的输出如下所示:

 CLANG ARITHMETIC UNDEFINED at <add.c, (9:11)> : Op: +, Reason : Signed Addition Overflow, BINARY OPERATION: left (int32): 2147483647 right (int32): 1 

CERT开发了一种使用“as-if”无限范围(AIR)整数模型检测和报告带符号整数溢出,无符号整数回绕和整数截断的新方法。 CERT发布了一个描述该模型的技术报告 ,并基于GCC 4.4.0和GCC 4.5.0生成了一个工作原型。

AIR整数模型要么产生一个相当于使用无限范围整数获得的值,要么导致运行时间约束冲突。 Unlike previous integer models, AIR integers do not require precise traps, and consequently do not break or inhibit most existing optimizations.

Calculate the results with doubles. They have 15 significant digits. Your requirement has a hard upper bound on c of 10 8 — it can have at most 8 digits. Hence, the result will be precise if it's in range, and it will not overflow otherwise.

Another variant of solution using assembler is an external procedure. This example for unsigned integer multiplication using g++ and fasm under linux x64.

This procedure multiplies two unsigned integer arguments (32 bits) (according to specification for amd64 (section 3.2.3 Parameter Passing)

If the class is INTEGER, the next available register of the sequence %rdi,%rsi,%rdx,%rcx,%r8 and %r9 is used

(edi and esi registers in my code)) and returns the result or 0 if an overflow has occured.

 format ELF64 section '.text' executable public u_mul u_mul: MOV eax, edi mul esi jnc u_mul_ret xor eax, eax u_mul_ret: ret 

testing:

 extern "C" unsigned int u_mul(const unsigned int a, const unsigned int b); int main() { printf("%u\n", u_mul(4000000000,2));//0 printf("%u\n", u_mul(UINT_MAX/2,2));//ok return 0; } 

link program with asm object file. In my case in Qt Creator add it to LIBS in a .pro file

Try this macro to test the overflow bit of 32-bit machines (adapted the solution of Angel Sinigersky)

 #define overflowflag(isOverflow){ \ size_t eflags; \ asm ("pushfl ;" \ "pop %%eax" \ : "=a" (eflags)); \ isOverflow = (eflags >> 11) & 1;} 

I defined it as a macro because otherwise the overflow bit would have been overwritten.

Subsequent is a little application with the code segement above:

 #include <cstddef> #include <stdio.h> #include <iostream> #include <conio.h> #if defined( _MSC_VER ) #include <intrin.h> #include <oskit/x86> #endif using namespace std; #define detectOverflow(isOverflow){ \ size_t eflags; \ asm ("pushfl ;" \ "pop %%eax" \ : "=a" (eflags)); \ isOverflow = (eflags >> 11) & 1;} int main(int argc, char **argv) { bool endTest = false; bool isOverflow; do { cout << "Enter two intergers" << endl; int x = 0; int y = 0; cin.clear(); cin >> x >> y; int z = x * y; detectOverflow(isOverflow) printf("\nThe result is: %d", z); if (!isOverflow) { std::cout << ": no overflow occured\n" << std::endl; } else { std::cout << ": overflow occured\n" << std::endl; } z = x * x * y; detectOverflow(isOverflow) printf("\nThe result is: %d", z); if (!isOverflow) { std::cout << ": no overflow ocurred\n" << std::endl; } else { std::cout << ": overflow occured\n" << std::endl; } cout << "Do you want to stop? (Enter \"y\" or \"Y)" << endl; char c = 0; do { c = getchar(); } while ((c == '\n') && (c != EOF)); if (c == 'y' || c == 'Y') { endTest = true; } do { c = getchar(); } while ((c != '\n') && (c != EOF)); } while (!endTest); } 

You can't access the overflow flag from C/C++.

我不同意这一点。 You could write some inline asm and use a jo (jump overflow) instruction assuming you are on x86 to trap the overflow. Of course you code would no longer be portable to other architectures.

look at info as and info gcc .

Catching Integer Overflows in C points out a solution more general than the one discussed by CERT (it is more general in term of handled types), even if it requires some GCC extensions (I don't know how widely supported they are).

Inline assembly lets you check the overflow bit directly. If you are going to be using C++, you really should learn assembly.

A clean way to do it would be to override all operators (+ and * in particular) and check for an overflow before perorming the operations.

@MSalters: Good idea.

If the integer calculation is required (for precision), but floating point is available, you could do something like:

 uint64_t foo( uint64_t a, uint64_t b ) { double dc; dc = pow( a, b ); if ( dc < UINT_MAX ) { return ( powu64( a, b ) ); } else { // overflow } } 

To expand on Head Geek's answer, there is a faster way to do the addition_is_safe ;

 bool addition_is_safe(unsigned int a, unsigned int b) { unsigned int L_Mask = std::numeric_limits<unsigned int>::max(); L_Mask >>= 1; L_Mask = ~L_Mask; a &= L_Mask; b &= L_Mask; return ( a == 0 || b == 0 ); } 

This uses machine-architecture safe, in that 64-bit and 32-bit unsigned integers will still work fine. Basically, I create a mask that will mask out all but the most significant bit. Then, I mask both integers, and if either of them do not have that bit set, then addition is safe.

This would be even faster if you pre-initialize the mask in some constructor, since it never changes.

x86 instruction set includes unsigned multiply instruction that stores the result to two registers. To use that instruction from C one can write following code in 64bit program (gcc):

 unsigned long checked_imul(unsigned long a, unsigned long b) { __int128 res = (__int128)a * (__int128)b; if ((unsigned long)(res >> 64)) printf("overflow in integer multiply"); return (unsigned long)res; } 

For 32bit program one needs to make result 64 bit and parameters 32bit.

Alternative is to use compiler depend instincts to check the flag register. GCC documentation for overflow instincts can be found from https://gcc.gnu.org/onlinedocs/gcc/Integer-Overflow-Builtins.html

It depends what you use it for. Performing unsigned long(DWORD) addition or Multiplication the best solution is to use ULARGE_INTEGER.

ULARGE_INTEGER is a structure of two DWORDs. The full value can be accessed as "QuadPart" while the hi DWORD is accessed as "HighPart" and the low DWORD is accessed as "LowPart"

例如:

DWORD My Addition(DWORD Value_A,DWORD Value_B) { ULARGE_INTEGER a,b;

  b.LowPart = Value_A; // a 32 bit value(up to 32 bit) b.HighPart = 0; a.LowPart = Value_B; // a 32 bit value(up to 32 bit) a.HighPart = 0; a.QuadPart += b.QuadPart; // if a.HighPart // Then a.HighPart contains the overflow(carry) return (a.LowPart + a.HighPart) 

// any overflow is stored in a.HighPart(up to 32 bits)

The simple way to test for overflow is to do validation by checking whether the current value is less than the previous value. For example, suppose you had a loop to print the powers of 2:

 long lng; int n; for (n = 0; n < 34; ++n) { lng = pow (2, n); printf ("%li\n", lng); } 

Adding overflow checking the way that I described results in this:

 long signed lng, lng_prev = 0; int n; for (n = 0; n < 34; ++n) { lng = pow (2, n); if (lng <= lng_prev) { printf ("Overflow: %i\n", n); /* Do whatever you do in the event of overflow. */ } printf ("%li\n", lng); lng_prev = lng; } 

It works for unsigned values as well as both positive and negative signed values.

Of course, if you wanted to do something similar for decreasing values instead of increasing values, you would flip the <= sign to make it >= , assuming the behaviour of underflow is the same as the behaviour of overflow. In all honesty, that's about as portable as you'll get without access to a CPU's overflow flag (and that would require inline assembly code, making your code non-portable across implementations anyway).

To perform an unsigned multiplication without overflowing in a portable way the following can be used:

 ... /* begin multiplication */ unsigned multiplicand, multiplier, product, productHalf; int zeroesMultiplicand, zeroesMultiplier; zeroesMultiplicand = number_of_leading_zeroes( multiplicand ); zeroesMultiplier = number_of_leading_zeroes( multiplier ); if( zeroesMultiplicand + zeroesMultiplier <= 30 ) goto overflow; productHalf = multiplicand * ( c >> 1 ); if( (int)productHalf < 0 ) goto overflow; product = productHalf * 2; if( multiplier & 1 ){ product += multiplicand; if( product < multiplicand ) goto overflow; } ..../* continue code here where "product" is the correct product */ .... overflow: /* put overflow handling code here */ int number_of_leading_zeroes( unsigned value ){ int ctZeroes; if( value == 0 ) return 32; ctZeroes = 1; if( ( value >> 16 ) == 0 ){ ctZeroes += 16; value = value << 16; } if( ( value >> 24 ) == 0 ){ ctZeroes += 8; value = value << 8; } if( ( value >> 28 ) == 0 ){ ctZeroes += 4; value = value << 4; } if( ( value >> 30 ) == 0 ){ ctZeroes += 2; value = value << 2; } ctZeroes -= x >> 31; return ctZeroes; } 
 #include <stdio.h> #include <stdlib.h> #define MAX 100 int mltovf(int a, int b) { if (a && b) return abs(a) > MAX/abs(b); else return 0; } main() { int a, b; for (a = 0; a <= MAX; a++) for (b = 0; b < MAX; b++) { if (mltovf(a, b) != (a*b > MAX)) printf("Bad calculation: a: %db: %d\n", a, b); } }