如果我在C中执行以下代码:
#include <stdint.h>
uint16_t a = 4000;
uint16_t b = 8000;
int32_t c = a - b;
printf("%d", c);
Run Code Online (Sandbox Code Playgroud)
它正确打印'-4000'作为结果.但是,我有点困惑:当从另一个中减去一个更大的无符号整数时,不应该有算术溢出吗?这里有什么施法规则?这个问题看起来有点愚蠢,所以任何参考文献都会非常感激.
我在.net程序中见证了一个奇怪的行为:
Console.WriteLine(Int64.MaxValue.ToString());
// displays 9223372036854775807, which is 2^63-1, as expected
Int64 a = 256*256*256*127; // ok
Int64 a = 256*256*256*128; // compile time error :
//"The operation overflows at compile time in checked mode"
// If i do this at runtime, I get some negative values, so the overflow indeed happens.
Run Code Online (Sandbox Code Playgroud)
为什么我的Int64的行为就像它们是Int32的一样,虽然Int64.MaxValue似乎证实它们使用的是64位?
如果它是相关的,我使用32位操作系统,目标平台设置为"任何CPU"
为什么在C#中示例一个有效的,可编译的并且只是包装而示例B将无法编译?
一个
int val = 0;
val = val + Int32.MaxValue +2;
Run Code Online (Sandbox Code Playgroud)
要么
int val = Int32.MaxValue;
val++;
Run Code Online (Sandbox Code Playgroud)
乙
int val = 0;
val = 2147483647 + 1;
Run Code Online (Sandbox Code Playgroud)
要么
int val = 0;
int val = Int32.MaxValue + 1;
Run Code Online (Sandbox Code Playgroud)
默认情况下,我知道默认情况下不会检查算术异常,除非您使用配置中的checked方法,块或属性明确地这样做.我的问题更多地涉及编译器然后如何发生算术异常.
蟒2具有两个整数数据类型int和long,并自动将它们之间作为转换必要,特别是为了避免整数溢出.
我在Python中模拟C函数,我想知道是否有重新启用整数溢出的标准方法.对于nonce,我已经习惯了
overflow_point = maxint + 1
if value > overflow_point:
value -= 2 * overflow_point
Run Code Online (Sandbox Code Playgroud)
是否有更标准的方法来做同样的事情?
在Java算术运算期间,JVM不会抛出下溢或溢出异常.很多时候,我们遇到了意想不到的结果,并想知道出了什么问题.
在.NET技术的情况下,我们有溢出和Undeflow异常.
所以我的问题是,为什么Java设计不会在算术运算期间抛出此异常
我知道(INT_MIN/-1)溢出,但(INT_MIN%-1)没有溢出.至少这是两个编译器中发生的事情,一个是前c ++ 11(VC++ 2010),另一个是后c ++ 11 GCC 4.8.1
int x = INT_MIN;
cout << x / -1 << endl;
cout << x % -1 << endl;
Run Code Online (Sandbox Code Playgroud)
得到:
-2147483648
0
Run Code Online (Sandbox Code Playgroud)
此行为标准是定义的还是实现定义的?还有其他任何情况下除法操作会溢出吗?并且是否存在模数运算符溢出的情况?
为了清楚和简单,我将缩短以下数字如下:
?170,141,183,460,469,231,731,687,303,715,884,105,728 如 -170…728170,141,183,460,469,231,731,687,303,715,884,105,727 如 170…727这些数字表示128位有符号整数(__int128 in gcc)的最小值和最大值.
我为这种数据类型实现了用户定义的文字(原始文字),因为gcc没有提供一种定义这种类型常量的方法:_u128for unsigned __int128和_i128for __int128.
减号不是UDL的一部分,但是应用于UDL结果的一元减号运算符.
因此对于a -ddddd_i128(其中d是一个数字),UDL计算带有正值的有符号 __int128,ddddd然后编译器将对其应用一元减运算符.到现在为止还挺好.
问题在于-170…128_i128(应该是有效值__int128):
UDL计算正好在范围之外的带符号 __int128正数,导致未定义行为(有符号整数溢出).170…128__int128
使用UDL表示此数字常量的任何解决方案?
我的UDL被声明(现在只是一个非constexpr,loopy版本)(它们是原始文字):
unsigned __int128 operator"" _u128(char const *str);
__int128 operator"" _i128(char const *str);
Run Code Online (Sandbox Code Playgroud)
一些用法:
1000000000000000000000000000000000_i128
-1000000000000000000000000000000000_i128
-170141183460469231731687303715884105728_i128 // <-- this has UB
170141183460469231731687303715884105727_u128
340282366920938463463374607431768211455_u128
Run Code Online (Sandbox Code Playgroud)
我知道有-170…728多种方法可以用各种方式定义常量,比如位移,数学运算,但我希望能够以一致的方式创建它,例如我不想要这种情况:你可以创建任何常量这个UDL,除了-170…728_i128你必须使用额外的技巧.
一般来说,如何防止C编程语言中发生整数溢出?我的意思是,有什么功能可以防止吗?最后,整数溢出是否会让我像缓冲区溢出等那样被黑客攻击?
对于大多数可能溢出的操作符,Rust 提供了一个检查版本。例如,要测试加法是否溢出,可以使用checked_add:
match 255u8.checked_add(1) {
Some(_) => println!("no overflow"),
None => println!("overflow!"),
}
Run Code Online (Sandbox Code Playgroud)
这打印"overflow!". 还有一个checked_shl, 但根据文档,它只检查移位是否大于或等于self. 这意味着虽然这个:
match 255u8.checked_shl(8) {
Some(val) => println!("{}", val),
None => println!("overflow!"),
}
Run Code Online (Sandbox Code Playgroud)
被捕获并打印"overflow!",这是:
match 255u8.checked_shl(7) {
Some(val) => println!("{}", val),
None => println!("overflow!"),
}
Run Code Online (Sandbox Code Playgroud)
只是打印128,显然没有捕捉到溢出。向左移动时检查任何类型溢出的正确方法是什么?
假设这uint是我的定点平台上最大的整数类型,我有:
uint func(uint a, uint b, uint c);
Run Code Online (Sandbox Code Playgroud)
这需要返回一个很好的近似值a * b / c。
的值c大于 的值a和 的值b。
所以我们肯定知道 的值a * b / c将适合 a uint。
但是,a * b本身的值会溢出 a 的大小uint。
因此,计算 的值的一种方法a * b / c是:
return a / c * b;
Run Code Online (Sandbox Code Playgroud)
甚至:
if (a > b)
return a / c * b;
return b / c * a;
Run Code Online (Sandbox Code Playgroud)
但是, 的值c …