c语言整数溢出
㈠ 如何判断整数数据的溢出
整数溢出,如何判断整数溢出 收藏
c语言中存在两类整数算术运算,有符号运算和无符号运算。在无符号运算里,没有了符号位,所以是没有溢出的概念的。
所有的无符号运算都是以2的n次方为模。如果算术运算符的一个操作数是有符号书,另一个是无符号数,那么有符号数
会被转换为无符号数(表示范围小的总是被转换为表示范围大的),那么溢出卜族也不会发生。但是,当两个操作数都是有符号数
时,溢出就有可能山弊此发生。而且溢出的结果是未定义的。当一个运算的结果发生溢出时,任何假设都是不安全的。
例如,假定a和b是两个非负的整型变量(有符号),我们需要检查a+b是否溢出,一种想当然的方式是:
if (a + b < 0)
溢出;
实际上,在现实世界里,逗迅这并不能正常运行。当a+b确实发生溢出时,所有关于结果如何的假设均不可靠。比如,在某些
机器的cpu,加法运算将设置一个内部寄存器为四种状态:正,负,零和溢出。在这种机器上,c编译器完全有理由实现以上
的例子,使得a+b返回的不是负,而是这个内存寄存器的溢出状态。显然,if的判断会失败。
一种正确的方式是将a和b都强制转换为无符号整数:
if ( (unsigned)a + (unsigned)b > INT_MAX)
溢出;
这里的int_max值为有符号整型的最大值。在一般的编译器里是一个预定义的常量。ANSI C在limits里定义了INT_MAX,值为
2的31次方-1.
不需要用到无符号算数运算的另一种可行方法是:
if (a > INT_MAX - b )
溢出;
PS : 有符号数的最高位(31位)为符号位,最高位为0的时候,表示正,为1的时候表示负。运算时,符号位不参加运算,但是如果两个数相加,30位需要进1时,那么即表示溢出。
㈡ 在c语言编程中,如何避免整数运算溢出问题
要么用足够大的数据类型,要么使用数组自己实现大数的运算,亦可直接使用GMP库实现任意精度数学运算
㈢ C语言编程问题,数据溢出。
你的算法有问题:
你这个程序的算法没有你想的这么容易,因为实际上中间你是在做幂运算,而幂运算是非常容易溢出的;
但是考虑到实际上你只是需要输出后面三位数字即可,那么按照乘法(幂运算其实是乘法运算)的规则,我们知道其实影响最后三位的是两个乘数的后三位,高于后三位的是不参与对乘积的后三位的影响的{(1000*x1+y1)*(1000*x1+y1),分析一下就知道了}。
所以,基于以上分析,我们只要将每一次乘积的后三位拿出来进行运算即可。
即你的进行幂运算的这段代码要改(未调试):
while (i<=n)
{
j*=a;
j=%1000;
i++;
}
如果还怕出现溢出,先将a也取余数就可以了。
㈣ C语言中怎么处理溢出
C
中调用积运算符之后做溢出检测已经太晚,但调用和运算符之后做检测则一点也不迟,
所以你可以通过对和运算结果的检测实现能检测溢出的积运算,因为
a
*
b
既是
a
个
b
的和:
-5000000
*
1374389539
等于
-(5000000
*
1374389539)。括号里是
5000000
个
1374389539
的和。
我把能检测溢出的和运算包在
add(
)
里,然后在
multiply(
)
里重复调用
add(
)。
add(
)
怎么检测溢出?
和运算的结果若溢出将导致数值的环绕。上溢导致往下环绕,下溢导致往上环绕。
边界状况:
(1)最轻微的上溢是
INT_MAX
+
1
:结果是
INT_MIN。
(2)最严重的上溢是
INT_MAX
+
INT_MAX
:结果是
-2。
(3)最轻微的下溢是
INT_MIN
-
1
:结果是
INT_MAX。
(4)最严重的下溢是
INT_MIN
-
INT_MIN
:结果是
0。
结论:
(1)所有上溢结果都小于任何一个操作数。
(2)所有下溢结果都大于任何一个操作数。
所以
add(
)
可以用结果和任意选定的一个参数判断溢出,并以落选的参数判断溢出的方向。
add(
)
无法以返回值举报溢出,所以采用
strtol(
)
的举报方法。
不同于
strtol(
)
的是,若没有溢出,add(
)
会把
0
赋值给
errno。
multiply(
)
在这方面跟
add(
)
一样。
#include<stdio.h>
#include<errno.h>
/*
errno,
ERANGE
*/
/*
*
Returns
the
sum
of
a
and
b,
with
overflow
and
underflow
check.
*
If
overflow
or
underflow
occurred,
sets
errno
to
ERANGE,
else
to
0.
*/
int
add(
int
a,
int
b
)
{
int
result
=
a
+
b;
if(
b
>
0
&&
result
>
a
||
b
<=
0
&&
result
<=
a
)
errno
=
0;
else
errno
=
ERANGE;
return
result;
}
/*
*
Returns
the
proct
of
a
and
b
obtained
through
repeated
call
of
add(
).
*
Affects
errno
exactly
as
add(
)
does.
*/
int
multiply(
int
a,
int
b
)
{
int
sign_of_a
=
1,
result
=
0,
i
=
0;
/*
Keep
the
sign
of
multiplier
off
the
loop
sentinel.
*/
if(
a
<
0
)
{
sign_of_a
=
-1;
a
*=
-1;
}
/*
Have
to
reset
errno
here
because
it
won't
be
updated
if
a
is
0.
*/
errno
=
0;
while(
i++
<
a
)
{
result
=
add(
result,
b
);
if(
errno
==
ERANGE
)
break;
}
return
result
*
sign_of_a;
}
int
main(
)
{
int
result;
/*
Operands
too
huge:
sure
overflow.
*/
result
=
multiply(
-5000000,
1374389539
);
if(
errno
==
ERANGE
)
perror(
"Uh
oh"
);
else
printf(
"%d\n",
result
);
/*
Small
operands:
safe.
*/
result
=
multiply(
49,
-972
);
if(
errno
==
ERANGE
)
perror(
"Uh
oh"
);
else
printf(
"%d\n",
result
);
}
当然,应付溢出的最佳方法还是防范:充分了解数据的范围,选择恰当的变量类型。
也许你正考虑改用不需要你担心整数类型溢出的语言。考虑过
Python
吗?
㈤ 如何判断整数是否溢出
根据存储的空间和有无符号位。
例如c或java当中的int型,使用32位,4个字节存储,有符号位。其能存储2^32种不同数据。可存储的数据在-2^31~2^31-1这个范围内,超出则范围则溢出。
若使用不带符号位,则范围为0~2^32-1。
用更加简单的例子,如果使用4位来存储,只能存储2^4=16种不同数据。如果不带符号位,则存储范围为0~15,超出则溢出。如果带符号位,则范围为-8~7,超出则溢出。
在实际编程中,某些编译器会在特定情况下提示溢出问题,但更多情况需要自己处理溢出问题。
有什么具体需求可以在追问中提出。