在VC里能用
unsigned short i=60000;
try{ i+=6000; }catch(加法溢出异常 ... ){ ... }
try{ i*=60000; }catch(乘法溢出异常 ... ){ ... }
这种结构处理运算溢出吗?如果可以,“溢出异常”的类名是什么?
如果不行,怎样才能得知运算溢出?
在别的平台上如Linux 的C++或Unix 的基本C 里面又如何检测运算溢出?
unsigned short i=60000;
try{ i+=6000; }catch(加法溢出异常 ... ){ ... }
try{ i*=60000; }catch(乘法溢出异常 ... ){ ... }
这种结构处理运算溢出吗?如果可以,“溢出异常”的类名是什么?
如果不行,怎样才能得知运算溢出?
在别的平台上如Linux 的C++或Unix 的基本C 里面又如何检测运算溢出?
virtual int overflow( int nCh = EOF ) = 0;
在结果不太在的情况下一个符号整数是否溢出可以判断它是否小于0
无符号整数是否溢出可以判断它是否小于原值.
如果结果较大,最好用容量大一点的类型(如long)然后判断它是否超出你要的范围.
“C语言对整数是不检测溢出的” -- 那么怎么用C语言写出别的检查溢出的程序的(如Basic、fortran等等)?
“无符号整数溢出可以判断它是否小于原值” -- 你试试做乘法,溢出后仍然会大于原值。
“用容量大一点的类型判断它是否超出你要的范围”-- 我要得知64bit整数(__int64)的运算是否溢出怎么办?TO wacky(笨笨狗):
“用asm检测状态寄存器”-- 在PC平台上我会,可别的平台呢?苹果机、掌上电脑、RISC CPU等等,难道一个要检查运算溢出的C程序在这些平台上移植时都要用asm改写相关代码么?
有这样一些代码,表面看起来很正确。但是由于实现上存在着微妙的问题,执行却失败了,这是最严重的错误。“简单字符”就是这种性质的错误。下面的代码也具有这样的错误,这段代码用作初始化标准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程序秘诀〉
1:
编一程序,建立有20个关键字表,并把该结果存入"KEY.DAT"中.要求采用二维数组方式.
2:能把从终端读入的一个字符串中的小写字母全部转换成大写字母,然后输出到一个磁盘文件"TEST"中保存,并在屏幕上输出转换之后的字符串.(用惊叹号字符!表示输入字符的结束)
万分感谢大家了。
我想知道Unix平台上的Frotran, Pascal, basic 以及PC平台上的VB,
写这些语言的时候难道真是用汇编代码实现其运算并检查溢出的吗?
PC倒也罢了,难道Unix在不同类型CPU上移植时,这些与运算有关的模块都要重新手工书写吗?
恩,或许是的。
我多失望噢。
无符号减法溢出判断:a-b > a
无符号乘法溢出判断:程序必须保证乘法不溢出而不是算完后判断是否溢出。两个n位的整数相乘结果仍是n位的可能性有多大?一般都是用2n位来表示乘法结果。
当然,必要的时候可以用特殊的方法实现(这正是这里讨论的问题)“无符号整数溢出可以判断它是否小于原值” -- 你试试做乘法,溢出后仍然会大于原值。
我前面有前提,"在结果不太大的情况下"“用容量大一点的类型判断它是否超出你要的范围”-- 我要得知64bit整数(__int64)的运算是否溢出怎么办?
我当然指的是有容量大一点的类型的情况下当然,还有办法.例如,求a+b (signed long,b>0)
if(b>0x7fffffff-a)
//overflow();
else
//a+b;
__int64没用过(我一直用的TC),但可类推;乘法也可类推实在不行,你愿意复杂些还可自己编程解决,100位,200位十进制的数我都用过
我不相信以简洁著称的C语言会不包括简单的溢出检测方法。
我认为在C里面应该封装这个功能而且对所有平台可用。所以提出这个问题。
示例!
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);
}
}
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;
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;
}
给大家调试吧!
#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;
}
尽管没有达到我的期望(也怪我没问得足够详细),
但是就你付出的心血我也该结贴了。
其实更方便的方法就是插入汇编代码:
JO 溢出跳转;
JNO 不溢出则跳转;
只是我固执地认为C语言应该简易实现溢出检测,才来发问。
问题的最后结果是令我失望的。