正确获取INT_MIN的绝对值的方法
我想在unsigned中执行一些算术,并且需要采用负int的绝对值,类似于
do_some_arithmetic_in_unsigned_mode(int some_signed_value) { unsigned int magnitude; int negative; if(some_signed_value<0) { magnitude = 0 - some_signed_value; negative = 1; } else { magnitude = some_signed_value; negative = 0; } ...snip... }
但是INT_MIN可能有问题,0 – 如果在带符号算术中执行,INT_MIN是UB。 在C中执行此操作的标准/健壮/安全/有效方法是什么?
编辑:
如果我们知道我们是2补码,那么隐式转换和显式位操作可能是标准的吗? 如果可能的话,我想避免这种假设。
do_some_arithmetic_in_unsigned_mode(int some_signed_value) { unsigned int magnitude=some_signed_value; int negative=some_signed_value<0; if (negative) { magnitude = (~magnitude) + 1; } ...snip... }
从有符号到无符号的转换是明确定义的:您获得相应的代表模2 N. 因此,以下将给出n
的正确绝对值:
int n = /* ... */; unsigned int abs_n = n < 0 ? UINT_MAX - ((unsigned int)(n)) + 1U : (unsigned int)(n);
更新:正如@ aka.nice建议的那样,我们实际上可以用UINT_MAX + 1U
代替UINT_MAX + 1U
:
unsigned int abs_n = n < 0 : -((unsigned int)(n)) : (unsigned int)(n);
在否定的情况下,取some_signed_value+1
。 否定它(这是安全的,因为它不能是INT_MIN
)。 转换为无符号。 然后加一个;
您始终可以测试>= -INT_MAX
,这始终是定义良好的。 唯一令人感兴趣的是INT_MIN < -INT_MAX
和some_signed_value == INT_MIN
。 您必须单独测试该案例。
static unsigned absolute(int x) { if (INT_MIN == x) { /* Avoid tricky arithmetic overflow possibilities */ return ((unsigned) -(INT_MIN + 1)) + 1U; } else if (x < 0) { return -x; } else { return x; } }