在VC里能用
unsigned short i=60000;
try{  i+=6000; }catch(加法溢出异常 ... ){ ... }
try{  i*=60000; }catch(乘法溢出异常 ... ){ ... }
这种结构处理运算溢出吗?如果可以,“溢出异常”的类名是什么?
如果不行,怎样才能得知运算溢出?
在别的平台上如Linux 的C++或Unix 的基本C 里面又如何检测运算溢出?

解决方案 »

  1.   

    CUP里面的状态寄存器都有1位用于标志溢出的。C语言肯定有函数检测这一位的,而且是通用的,无论什么CPU都行的,这是什么函数?
      

  2.   

    可以象楼上的用asm检测状态寄存器的溢出标志位,也可以用stdio C/C++中的流缓冲中的streambuf::overflow来检测。
    virtual int overflow( int nCh = EOF ) = 0;
      

  3.   

    流缓冲的overflow和整数溢出是两回事吧?C语言对整数是不检测溢出的,它只是简单把超出部分"切掉".
     在结果不太在的情况下一个符号整数是否溢出可以判断它是否小于0
    无符号整数是否溢出可以判断它是否小于原值.
    如果结果较大,最好用容量大一点的类型(如long)然后判断它是否超出你要的范围.
      

  4.   

    To yizhili(梨子):大错特错!!!
    “C语言对整数是不检测溢出的” -- 那么怎么用C语言写出别的检查溢出的程序的(如Basic、fortran等等)?
    “无符号整数溢出可以判断它是否小于原值” -- 你试试做乘法,溢出后仍然会大于原值。
    “用容量大一点的类型判断它是否超出你要的范围”-- 我要得知64bit整数(__int64)的运算是否溢出怎么办?TO  wacky(笨笨狗):
    “用asm检测状态寄存器”-- 在PC平台上我会,可别的平台呢?苹果机、掌上电脑、RISC CPU等等,难道一个要检查运算溢出的C程序在这些平台上移植时都要用asm改写相关代码么?
      

  5.   

    Basic, fortran是用C语言写的吗??"C语言对整数是不检测溢出的",这句话是教科书上讲的,难道错了吗?
      

  6.   

    数据上溢或下溢
    有这样一些代码,表面看起来很正确。但是由于实现上存在着微妙的问题,执行却失败了,这是最严重的错误。“简单字符”就是这种性质的错误。下面的代码也具有这样的错误,这段代码用作初始化标准tolower宏的查寻表。
    char chToLower[ UCHAR_MAX+1 ];
    void BuildToLowerTable( void ) /* ASCII版本*/
        {
           unsigned char ch;
           /* 首先将每个字符置为它自己 */
           for (ch=0; ch <= UCHAR_MAX;ch++)
              chToLower[ch] = ch;
    /* 现将小写字母放进大写字母的槽子里 */
    for( ch = ‘A’; ch <= ‘Z’; ch++ )
    chToLower[ch] = ch +’a’ – ‘A’;
    }
    ……
    #define tolower(ch)(chToLower[(unsigned char)(ch)])
    尽管代码看上去很可靠,实际上BuildToLowerTable很可能使系统挂起来。看一下第一个循环,什么时候ch大于 UCHAR_MAX呢?如果你认为“从来也不会”,那就对了。如果你不这样认为,请看下面的解释。
    假设ch等于UCHAR_MAX,那么循环语句理应执行最后一次了。但是就在最后测试之前,ch增加为UCHAR_MAX+1,这将引起ch上溢为0。因此,ch将总是小于等于UCHAR_MAX,机器将进行无限的循环。
    通过查看代码,这个问题还不明显吗?
    变量也可能下溢,那将会造成同样的困境。下面是实现memchr函数的一段代码。它的功能是通过查寻存储块,来找到第一次出现的某个字符。如果在存储块中找到了该字符,则返问指向该字符的指针,否则,返回空指针。象上面的BuildToLowerTable一样,memchr的代码看上去似乎是正确的,实际上却是错误的。
    void * memchr( void *pv, unsigned char ch, size_t size )
    {
    unsigned char *pch = (unsigned char *) pv;
    while( -- size >=0 )
    {
    if( *pch == ch )
    return (pch );
    pch++;
    }
    return( NULL );
    }
    循环什么时候终止?只有当size小于0时,循环才会终止。可是size会小于0吗?不会,因为size是无符号值,当它为0时,表达式--size将使其下溢而成为类型size_t定义的最大无符号位。
    这种下溢错误比BuldToLowerTable中的错误更严重。假如,memchr在存储块中找到了字符,它将正确地工作,即使没有找到字符,它也不致使系统悬挂起来.而坚持查下去,直到在某处找到了这个字符并返回指向该字符的指针为止。然而,在某些应用中也可能产生非常严重的错误。
    我们希望编译程序能对“简单字符”错误和上面两种错误发出警告。但是几乎没有任何编译程序对这些问题给出警告。因此,在编译程序的销售商说有更好的编译代码生成器之前,程序员将依靠自已来发现上溢和下溢错误。
    但是,如果用户按照本书第4章的建议逐条跟踪代码,那么这三种错误就都能发现。用户将会发现,*pch在与0xff比较之前已经转换为0xffff,ch上溢为0,size下溢为0xffff。由于这些错误太微妙,可能用户花几小时时间仔细阅读代码,也不会发现上溢错,但是如果查看在调试状态下该程序的数据流,就能很容易地发现这些错误。经常反问:“这个变量表达式会上溢或下溢吗?”
             ----------摘自《Microsoft编写优质无错C程序秘诀〉
      

  7.   

    我初学C语言,请各位高手帮忙做两个题:
    1:
    编一程序,建立有20个关键字表,并把该结果存入"KEY.DAT"中.要求采用二维数组方式.
    2:能把从终端读入的一个字符串中的小写字母全部转换成大写字母,然后输出到一个磁盘文件"TEST"中保存,并在屏幕上输出转换之后的字符串.(用惊叹号字符!表示输入字符的结束)
       万分感谢大家了。
      

  8.   

    哎,看来是没法了。
    我想知道Unix平台上的Frotran, Pascal, basic 以及PC平台上的VB,
    写这些语言的时候难道真是用汇编代码实现其运算并检查溢出的吗?
    PC倒也罢了,难道Unix在不同类型CPU上移植时,这些与运算有关的模块都要重新手工书写吗?
    恩,或许是的。
    我多失望噢。
      

  9.   

    无符号加法溢出判断:a+b < a
    无符号减法溢出判断:a-b > a
    无符号乘法溢出判断:程序必须保证乘法不溢出而不是算完后判断是否溢出。两个n位的整数相乘结果仍是n位的可能性有多大?一般都是用2n位来表示乘法结果。
      

  10.   

    居然说我大错特错!我也许称不上高手,但必竟用了6年的C语言了,它的这点小脾气还是知道的.“C语言对整数是不检测溢出的” -- 那么怎么用C语言写出别的检查溢出的程序的(如Basic、fortran等等)?
       当然,必要的时候可以用特殊的方法实现(这正是这里讨论的问题)“无符号整数溢出可以判断它是否小于原值” -- 你试试做乘法,溢出后仍然会大于原值。
       我前面有前提,"在结果不太大的情况下"“用容量大一点的类型判断它是否超出你要的范围”-- 我要得知64bit整数(__int64)的运算是否溢出怎么办?
       我当然指的是有容量大一点的类型的情况下当然,还有办法.例如,求a+b (signed long,b>0)
       if(b>0x7fffffff-a)
            //overflow();
       else 
            //a+b;
    __int64没用过(我一直用的TC),但可类推;乘法也可类推实在不行,你愿意复杂些还可自己编程解决,100位,200位十进制的数我都用过
      

  11.   

    我们都知道在X86兼容PC上用汇编代码 "JO 溢出处理子程序地址"即可。
    我不相信以简洁著称的C语言会不包括简单的溢出检测方法。
    我认为在C里面应该封装这个功能而且对所有平台可用。所以提出这个问题。
      

  12.   

    顺便说一句,try的异常处理是c++的标准定义之一。
      

  13.   

    溢出属于逻辑错误!只有自己捕获!最好判断他的符号位是否为1!
    示例!
    CL CPP /GX
    #include <iostream>using namespace std;class Integeroverflow
    {  public:
          Integeroverflow(int ix, int iy): x(ix), y(iy) {}
          Integeroverflow(int ix):x(ix),y(0) {}
          int get_x() const {return x;};
          int get_y() const {return y;};
       private:
          int x;
          int y;
    };
    //Also the catch clause will now look like:
    #define handleinterror(x) {if (((x) <INT_MIN) || ((x) > INT_MAX) || ((x)& 0x80000000)) throw Integeroverflow(x);};
    int main()
    {
    int x = 2147483647;
    try
    {
    x = x + 600000;
    cout << "x = " << x << endl;
    int y = x;
    handleinterror(x); }
    catch (Integeroverflow &iobj) // iobj is just an identifier
    {   cout << "Integer overflow caused by " << dec << iobj.get_x() << " and " << dec << iobj.get_y();
        exit(1);
    }
    }
      

  14.   

    错了!搞错了!:)不好意思!同意 Wugifer()我看只有重载操作符,载其中抛出异常了!!不然要每次计算时都要先判断操作!:)
      

  15.   

    只有利用标志寄存器了!
    int x = 2147483647; unsigned long dwEAX = 0;
    x = x + 600000;
    __asm PUSH EAX
    __asm PUSHFD
    __asm POP EAX
    __asm MOV dwEAX,EAX
    __asm POP EAX
    cout << " Processor Flags "<< hex << dwEAX << dec << endl;
    if (dwEAX &0x80) cout << "overflow " << endl;
      

  16.   

    判断溢出OF位
    bool IsOverFlow()
    {
    unsigned long dwEAX = 0;
    __asm PUSH EAX
    __asm PUSHFD
    __asm POP EAX
    __asm MOV dwEAX,EAX
    __asm POP EAX
    #ifdef _DEBUG
    cout << " Processor Flags "<< hex << dwEAX << dec << endl;
    if (dwEAX &0x80) cout << "overflow " << endl;
    #endif
    if (dwEAX &0x80)return true;
    else return false;
    }
      

  17.   

    弄好了!
    给大家调试吧!
    #include <iostream>
    #include <conio.h>
    using namespace std;
    int main(int argc, char* argv[])
    {
    signed int x = 2147483647;
    unsigned long dwEAX = 0; cout << "signed int x = INT_MAX + 600000" << endl;
    // cout << IsOverFlow() << endl;
    x = x + 600000;
    __asm PUSHFD
    __asm PUSH EAX
    __asm PUSHFD
    __asm POP EAX
    __asm MOV dwEAX,EAX
    __asm POP EAX
    __asm POPFD
    #ifdef _DEBUG
    cout << " Processor Flags "<< hex << dwEAX << dec << endl;
    if (dwEAX &0x00000800) cout << "overflow " << endl;
    #endif cout << "unsigned long y = ULONG_MAX" << endl;
    unsigned long y = 4294967295 ;
    __asm PUSHFD
    __asm PUSH EAX
    __asm PUSHFD
    __asm POP EAX
    __asm MOV dwEAX,EAX
    __asm POP EAX
    __asm POPFD
    #ifdef _DEBUG
    cout << " Processor Flags "<< hex << dwEAX << dec << endl;
    if (dwEAX &0x00000800) cout << "overflow " << endl;
    #endif // cout << IsOverFlow() << endl;
    cout << "unsigned long n = ULONG_MAX + 4294 " << endl;
    unsigned long n = 0;  // unsigned long type data never overflow
    n = 4294967295 + 4294;
    __asm PUSHFD
    __asm PUSH EAX
    __asm PUSHFD
    __asm POP EAX
    __asm MOV dwEAX,EAX
    __asm POP EAX
    __asm POPFD
    #ifdef _DEBUG
    cout << " Processor Flags "<< hex << dwEAX << dec << endl;
    if (dwEAX &0x00000800) cout << "overflow " << endl;
    #endif
    // cout << IsOverFlow() << endl;
    cout << "signed long z = LONG_MAX + 61470 " << endl;
    signed long z  = LONG_MAX ;
    z = z +  61470;
    __asm PUSHFD
    __asm PUSH EAX
    __asm PUSHFD
    __asm POP EAX
    __asm MOV dwEAX,EAX
    __asm POP EAX
    __asm POPFD
    #ifdef _DEBUG
    cout << " Processor Flags "<< hex << dwEAX << dec << endl;
    if (dwEAX &0x00000800) cout << "overflow " << endl;
    #endif
    cout << "z = LONG_MIN - 60000" << endl;
    z = LONG_MIN;
    z = z - 60000;
    __asm PUSHFD
    __asm PUSH EAX
    __asm PUSHFD
    __asm POP EAX
    __asm MOV dwEAX,EAX
    __asm POP EAX
    __asm POPFD
    #ifdef _DEBUG
    cout << " Processor Flags "<< hex << dwEAX << dec << endl;
    if (dwEAX &0x00000800) cout << "overflow " << endl;
    #endif
    cout << "z = LONG_MAX * 60000 "<< endl;
    z = LONG_MAX;
    z = z* 60000;
    __asm PUSHFD
    __asm PUSH EAX
    __asm PUSHFD
    __asm POP EAX
    __asm MOV dwEAX,EAX
    __asm POP EAX
    __asm POPFD
    #ifdef _DEBUG
    cout << " Processor Flags "<< hex << dwEAX << dec << endl;
    if (dwEAX &0x00000800) cout << "overflow " << endl;
    #endif
    getch();
    return 0;
    }
      

  18.   

    (战鹰)同志请休息一会了,你的精神让我佩服。
    尽管没有达到我的期望(也怪我没问得足够详细),
    但是就你付出的心血我也该结贴了。
    其实更方便的方法就是插入汇编代码:
     JO  溢出跳转;
     JNO 不溢出则跳转;
    只是我固执地认为C语言应该简易实现溢出检测,才来发问。
    问题的最后结果是令我失望的。