如何在C中安全地添加和钳制有符号整数



我有一个signed int类型的值,它总是被夹在例如±1073741824(2^30(之间。我应该能够安全地添加或减去任何任意值,如果和/差在范围之外,则被钳制(任何高于最大值的值都映射到最大值,任何低于最小值的值映射到最小值(。我有以下内容:

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和/或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;
}

另请参阅如何在没有未定义行为的情况下检查C中的有符号整数溢出?

另请参见C常见问题列表中的问题20.6b。

相关内容

  • 没有找到相关文章

最新更新