你如何检查算术运算是否会溢出?
How do you check if an arithmetic operation will overflow?
我来自于 Rust 和 How do I detect unsigned integer multiply overflow?,在 Rust 中他们有 checked_add
,它是这样实现的:
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_add(rhs);
if unlikely!(b) {None} else {Some(a)}
}
pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
(a as Self, b)
}
// can't find where this is implemented...
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
如果您尝试将两个 u8
大整数相加,编译器不允许您:
fn main() {
let a: u8 = 255;
let b: u8 = 255;
let c = a + b;
// ^^^^^ attempt to compute `u8::MAX + u8::MAX`, which would overflow
}
这在 C 中是如何完成的?我怎样才能在 JavaScript 中模拟这种事情?
例如,在 JavaScript。我想在 JavaScript 中你会检查它是否命中 Infinity
,就像在 Number.MAX_VALUE * 2 == Infinity
中一样。但是在 Rust 的情况下,我如何使用特定的低级 uint 数据类型来模拟它(或在 C 中)? (无需求助于已经解决它的 checked_add
辅助方法)。基本上我想知道如果数据类型不允许您溢出,您如何判断它是否会溢出。
我正在构建一种编程语言,所以想知道它是如何实现的。
具体来说,现在我要做的是,如果您有一个名为 get_next_power_of_2(u8)
的函数,它应该 return 一个 u8(如果适合),否则一个 u16。但并非在所有情况下都是 u16。所以我想知道如何首先检查它是否会溢出,如果溢出,则转换为更高的 int。
How is this done in C?
当更广泛的数学可用时,代码可以使用它。
int a,b;
...
int_twice_as_wide product = (int_twice_as_wide) a * b;
if (product < INT_MIN || product > INT_MAX) Handle_Overflow();
使用有符号整数数学运算,溢出是未定义的行为 (UB),因此当更广泛的数学运算不容易获得时,代码可以执行各种pre-tests 对于 + - * /
完成 here.
对于无符号数学,溢出“环绕”(一个模块UINT_MAX + 1
)。 + -
(下)很容易。除法只需要关注/ 0
.
unsigned a,b;
...
unsigned sum = a + b;
if (sum < a) Handle_Overflow();
unsigned *
与上面引用的 signed *
代码非常相似,但测试较少。
bool is_undefined_umult1(unsigned a, unsigned b) {
if (b > 0) {
return a > UINT_MAX / b;
}
return false;
}
it should return a u8 if it fits, otherwise a u16. But not a u16 in all cases.
C 函数不会 return 根据值的不同类型。相反考虑:
uint16_t unt8_mul(unt8_t a, unt8_t b) {
return (uint16_t) a * b;
}
对于 u8 * u8,避免 a * b
因为在 16 位系统上乘法是 有符号 ,乘积可能溢出并导致 UB。
如果您知道变量的大小,那么您也知道它们可以存储的最大值和最小值。
在 C 中,您将检查逆运算是否有效,例如:
#include <stdio.h>
int main()
{
// max value a 4-byte unsigned int can store is 0xFFFFFFFF
unsigned int UINT32_MAX = 0xFFFFFFFF;
// var_1 + var_2 would overflow,
// as an unsigned int can't hold 0x100000028 (0xFFFFFFFE + 0x2A)
unsigned int var_1 = 0xFFFFFFFE;
unsigned int var_2 = 0x2A;
// check the inverse operation, which can be stored in memory
// var_1 + var_2 > UINT32_MAX --> UINT32_MAX - var_2 < var_1
if (UINT32_MAX - var_2 < var_1) {
printf("Overflow\n");
} else {
printf("No overflow\n");
}
return 0;
}
我来自于 Rust 和 How do I detect unsigned integer multiply overflow?,在 Rust 中他们有 checked_add
,它是这样实现的:
pub const fn checked_add(self, rhs: Self) -> Option<Self> {
let (a, b) = self.overflowing_add(rhs);
if unlikely!(b) {None} else {Some(a)}
}
pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT);
(a as Self, b)
}
// can't find where this is implemented...
#[rustc_const_stable(feature = "const_int_overflow", since = "1.40.0")]
pub fn add_with_overflow<T: Copy>(x: T, y: T) -> (T, bool);
如果您尝试将两个 u8
大整数相加,编译器不允许您:
fn main() {
let a: u8 = 255;
let b: u8 = 255;
let c = a + b;
// ^^^^^ attempt to compute `u8::MAX + u8::MAX`, which would overflow
}
这在 C 中是如何完成的?我怎样才能在 JavaScript 中模拟这种事情?
例如,在 JavaScript。我想在 JavaScript 中你会检查它是否命中 Infinity
,就像在 Number.MAX_VALUE * 2 == Infinity
中一样。但是在 Rust 的情况下,我如何使用特定的低级 uint 数据类型来模拟它(或在 C 中)? (无需求助于已经解决它的 checked_add
辅助方法)。基本上我想知道如果数据类型不允许您溢出,您如何判断它是否会溢出。
我正在构建一种编程语言,所以想知道它是如何实现的。
具体来说,现在我要做的是,如果您有一个名为 get_next_power_of_2(u8)
的函数,它应该 return 一个 u8(如果适合),否则一个 u16。但并非在所有情况下都是 u16。所以我想知道如何首先检查它是否会溢出,如果溢出,则转换为更高的 int。
How is this done in C?
当更广泛的数学可用时,代码可以使用它。
int a,b;
...
int_twice_as_wide product = (int_twice_as_wide) a * b;
if (product < INT_MIN || product > INT_MAX) Handle_Overflow();
使用有符号整数数学运算,溢出是未定义的行为 (UB),因此当更广泛的数学运算不容易获得时,代码可以执行各种pre-tests 对于 + - * /
完成 here.
对于无符号数学,溢出“环绕”(一个模块UINT_MAX + 1
)。 + -
(下)很容易。除法只需要关注/ 0
.
unsigned a,b;
...
unsigned sum = a + b;
if (sum < a) Handle_Overflow();
unsigned *
与上面引用的 signed *
代码非常相似,但测试较少。
bool is_undefined_umult1(unsigned a, unsigned b) {
if (b > 0) {
return a > UINT_MAX / b;
}
return false;
}
it should return a u8 if it fits, otherwise a u16. But not a u16 in all cases.
C 函数不会 return 根据值的不同类型。相反考虑:
uint16_t unt8_mul(unt8_t a, unt8_t b) {
return (uint16_t) a * b;
}
对于 u8 * u8,避免 a * b
因为在 16 位系统上乘法是 有符号 ,乘积可能溢出并导致 UB。
如果您知道变量的大小,那么您也知道它们可以存储的最大值和最小值。 在 C 中,您将检查逆运算是否有效,例如:
#include <stdio.h>
int main()
{
// max value a 4-byte unsigned int can store is 0xFFFFFFFF
unsigned int UINT32_MAX = 0xFFFFFFFF;
// var_1 + var_2 would overflow,
// as an unsigned int can't hold 0x100000028 (0xFFFFFFFE + 0x2A)
unsigned int var_1 = 0xFFFFFFFE;
unsigned int var_2 = 0x2A;
// check the inverse operation, which can be stored in memory
// var_1 + var_2 > UINT32_MAX --> UINT32_MAX - var_2 < var_1
if (UINT32_MAX - var_2 < var_1) {
printf("Overflow\n");
} else {
printf("No overflow\n");
}
return 0;
}