检查C中的溢出

时间:2011-04-11 09:43:22

标签: c

让我们拥有

int a, b, c; // may be char or float, anything actually
c = a + b;

让int类型由4个字节表示。假设a + b需要1位多于4个字节(即,假设结果是1 00 .... 0(32个零,二进制))。这将导致C = 0,我确信计算机的微处理器会设置某种溢出标志。是否有内置的方法在C中检查这个?

我实际上正在构建一个1024位长的数字类型(例如,int是一个32位长的内置数字类型)。我尝试使用带有128个元素的unsigned char类型数组。我还需要对这些数字定义加法和减法运算。我已经编写了添加代码,但我在减法方面遇到了问题。我不需要担心得到负面结果,因为我称之为减法函数的方式总是确保减法的结果总是正的,但是为了实现减法函数我需要以某种方式得到减数的2的补码,它是我自定义的1024位数。

如果难以理解我的描述,我很抱歉。如果需要,我会详细说明。我包含了我的代码,用于添加函数和不完整的减法函数。 NUM_OF_WORDS是一个声明为

的常量

#define NUM_OF_WORDS 128

如果您不理解我的问题或我的代码的任何部分,请告诉我。

PS:我没有看到如何在此论坛上传附件,因此我将您引导至其他网站。我的代码可以在那里找到

click on download in this page

顺便说一句,我发现this 我打算替换INT_MAX by UCHAR_MAX因为我的1024位数字由char类型数组(8位变量)组成 这种检查是否适用于所有情况?

更新

是的我正在研究密码学 我需要为1024位大小的整数实现蒙哥马利乘法例程 我也考虑过使用GMP库,但却找不到如何使用它 我查了一个教程,经过一些小修改后,我能够在VC ++ 6中构建GMP项目文件,这导致了很多.obj文件,但现在我不知道如何处理它们。
如果我能编写自己的数据类型仍然会很好,因为它可以让我完全控制我的自定义数据类型的算术运算如何工作,而且我还需要能够将它从1024位扩展到更大的数字。未来。

7 个答案:

答案 0 :(得分:4)

如果您要添加无符号数字,则可以执行此操作

c = a+b;
if (c<a) {
  // you'll get here if and only if overflow has occurred
}

你甚至可能会发现你的编译器足够聪明,可以通过检查overflow或carry标志来实现它,而不是进行额外的比较。例如,我刚把它喂给gcc -O3 -S

unsigned int foo() {
  unsigned int x=g(), y=h();
  unsigned int z = x+y;
  return z<0 ? 0 : z;
}

并得到了代码的关键位:

movl  $0,   %edx
addl  %ebx, %eax
cmovb %edx, %eax

你会注意到没有额外的比较指示。

答案 1 :(得分:3)

与普遍看法相反,int溢出导致未定义的行为。这意味着一旦a + b溢出,使用此值(或做任何其他事情)就没有意义了。环绕是大多数机器在发生溢出时碰巧做的事情,但它们也可能爆炸。

要检查在添加两个非负整数inta时是否会发生b溢出,您可以执行以下操作:

if (INT_MAX - b < a) {
        /* int overflow when evaluating a+b */
}

这是因为如果a + b > INT_MAX,则INT_MAX - b < a,但INT_MAX - b不会溢出。

您必须特别注意b为否定的情况,这是读者留下的练习;)


关于您的实际目标:1024位数字与32位数字完全相同。选择完全不同的方法可能更有希望,例如,使用非常大的基数B表示数字,例如,链接的数字列表。通常,选择B使得B = sqrt(INT_MAX),因此数字的乘法不会溢出机器的int类型。

这样,您可以表示任意大数,其中“任意”表示“仅受可用主内存量的限制”。

答案 2 :(得分:1)

如果您使用的是未签名的号码,那么a <= UINT_MAXb <= UINT_MAXa + b >= UINT_MAX,则c = (a + b) % UINT_MAX将始终小于a和{ {1}}。这是唯一可能发生这种情况的情况。

所以你可以用这种方式检测溢出。

b

答案 3 :(得分:1)

可能对此主题有用的信息:

  1. Secure Coding in C and C++
  2. IntSafe library

答案 4 :(得分:0)

您可以基于C语言的特定功能构建解决方案。根据规范,当你添加两个无符号整数时,“结果值与真实结果的模2 ^ n一致”(Harbison和Steele的“C - 参考手册”)。这意味着您可以使用一些简单的算术检查来检测溢出:

#include <stdio.h>

int main() {
    unsigned int a, b, c;
    char *overflow;

    a = (unsigned int)-1;
    for (b = 0; b < 3; b++) {
        c = a + b;
        overflow = (a < b) ? "yes" : "no";
        printf("%u + %u = %u, %s overflow\n", a, b, c, overflow);
    }

    return 0;
}

答案 5 :(得分:0)

两个操作数和结果的x或MSB。此操作的结果是溢出标志。

但是,如果结果是否正确,那将无法显示。 (它可能是正确的结果,即使是溢出)例如3 +( - 1)是2个溢出。

为了确定使用带符号的算术,你需要检查两个operdas是否都是相同的符号(MSB的xor)。

答案 6 :(得分:-1)

一旦你向INT_MAX加1,你最终得到INT_MIN(即溢出) 在C中,没有可靠的方法来测试溢出,因为所有32个字节都用于表示整数(而不是状态标志)。您只能测试以查看您获得的号码是否在有效范围内,如您的链接。

你会得到答案,建议你可以测试if (c < a),但请注意你可以将a和/或b的值溢出到它们的加法形成一个大于a的数字的点(但仍然溢出)