C语言中怎么处理溢出
发布网友
发布时间:2022-04-29 18:13
我来回答
共5个回答
热心网友
时间:2023-10-29 17:18
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 吗?
热心网友
时间:2023-10-29 17:18
把int型换成long型
一般来说long型占64位
热心网友
时间:2023-10-29 17:18
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 吗?
热心网友
时间:2023-10-29 17:18
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 吗?
热心网友
时间:2023-10-29 17:18
把int型换成long型
一般来说long型占64位
热心网友
时间:2023-10-29 17:19
在现在的Windows平台下,长整型是long long或者__int64,是64位,而long应该是32位的,不是64的。
热心网友
时间:2023-10-29 17:19
长整型已经足够满足日常的使用了
热心网友
时间:2023-10-29 17:20
换长整型
热心网友
时间:2023-10-29 17:19
在现在的Windows平台下,长整型是long long或者__int64,是64位,而long应该是32位的,不是64的。
热心网友
时间:2023-10-29 17:19
长整型已经足够满足日常的使用了
热心网友
时间:2023-10-29 17:20
换长整型
热心网友
时间:2023-10-29 17:18
把int型换成long型
一般来说long型占64位
热心网友
时间:2023-10-29 17:19
在现在的Windows平台下,长整型是long long或者__int64,是64位,而long应该是32位的,不是64的。
热心网友
时间:2023-10-29 17:19
长整型已经足够满足日常的使用了
热心网友
时间:2023-10-29 17:18
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 吗?
热心网友
时间:2023-10-29 17:18
把int型换成long型
一般来说long型占64位
热心网友
时间:2023-10-29 17:19
在现在的Windows平台下,长整型是long long或者__int64,是64位,而long应该是32位的,不是64的。
热心网友
时间:2023-10-29 17:19
长整型已经足够满足日常的使用了
热心网友
时间:2023-10-29 17:20
换长整型
热心网友
时间:2023-10-29 17:20
换长整型