如何在 C 中安全地添加和限制有符号整数?
How can I safely add and clamp a signed integer in C?
我有一个 signed int
类型的值,它总是被限制在例如 ±1073741824 (2^30) 之间。我应该能够安全地添加或减去任何任意值,如果 sum/difference 在范围之外,它是 clamped (任何高于最大值的值都映射到最大值,并且任何低于最小值的值都映射到最小值)。我有以下内容:
signed int Min(signed int X, signed int Y) {
return X < Y ? X : Y;
}
signed int Max(signed int X, signed int Y) {
return X > Y ? X : Y;
}
signed int X;
void UpdateX(signed int Delta) {
X = Min(Max(X+Delta, -(1<<30)), (1<<30));
}
但是,如果 Delta and/or X 足够大或足够小以至于值上溢或下溢,这将调用 Undefined Behavior,因为在钳位之前存在 signed int
上溢。一种解决方案是临时使用更大的整数类型,但对于已经使用最大可用类型的其他情况,这不是一个选项。我如何安全地添加然后钳制 signed int
而不会冒调用未定义行为的风险?
您担心溢出是对的。检查溢出的明显技术是在溢出发生后 检测到它,如果涉及任何未定义的行为,这当然为时已晚。
标准技术是重新安排测试。而不是说:
if(X + Delta > MAX) { whoops! it overflowed; }
从两边减去 Delta
得到
if(X > MAX - Delta) { whoops! it overflowed; }
当然你也要考虑Delta
是否定的可能性。所以在你的情况下,我相信这样的事情会做到这一点:
#define MAX (1<<30)
void UpdateX(signed int Delta) {
if(Delta >= 0) X = (X <= MAX - Delta) ? X + Delta : MAX;
else X = (X >= -MAX - Delta) ? X + Delta : -MAX;
}
另见 How to check for signed integer overflow in C without undefined behaviour?
另见 Question 20.6b in the C FAQ list。
我有一个 signed int
类型的值,它总是被限制在例如 ±1073741824 (2^30) 之间。我应该能够安全地添加或减去任何任意值,如果 sum/difference 在范围之外,它是 clamped (任何高于最大值的值都映射到最大值,并且任何低于最小值的值都映射到最小值)。我有以下内容:
signed int Min(signed int X, signed int Y) {
return X < Y ? X : Y;
}
signed int Max(signed int X, signed int Y) {
return X > Y ? X : Y;
}
signed int X;
void UpdateX(signed int Delta) {
X = Min(Max(X+Delta, -(1<<30)), (1<<30));
}
但是,如果 Delta and/or X 足够大或足够小以至于值上溢或下溢,这将调用 Undefined Behavior,因为在钳位之前存在 signed int
上溢。一种解决方案是临时使用更大的整数类型,但对于已经使用最大可用类型的其他情况,这不是一个选项。我如何安全地添加然后钳制 signed int
而不会冒调用未定义行为的风险?
您担心溢出是对的。检查溢出的明显技术是在溢出发生后 检测到它,如果涉及任何未定义的行为,这当然为时已晚。
标准技术是重新安排测试。而不是说:
if(X + Delta > MAX) { whoops! it overflowed; }
从两边减去 Delta
得到
if(X > MAX - Delta) { whoops! it overflowed; }
当然你也要考虑Delta
是否定的可能性。所以在你的情况下,我相信这样的事情会做到这一点:
#define MAX (1<<30)
void UpdateX(signed int Delta) {
if(Delta >= 0) X = (X <= MAX - Delta) ? X + Delta : MAX;
else X = (X >= -MAX - Delta) ? X + Delta : -MAX;
}
另见 How to check for signed integer overflow in C without undefined behaviour?
另见 Question 20.6b in the C FAQ list。