一元减号和签名到无符号转换

blu*_*rni 11 c c++

这在技术上是否正确:

unsigned abs(int n)
{
    if (n >= 0) {
        return n;
    } else {
        return -n;
    }
}
Run Code Online (Sandbox Code Playgroud)

在我看来,如果-INT_MIN> INT_MAX,"-n"表达式在n == INT_MIN时可能会溢出,因为-INT_MIN超出了边界.但是在我的编译器上,这似乎工作正常......这是一个实现细节还是可以依赖的行为?

更长的版本

一点上下文:我正在为GMP整数类型(mpz_t)编写一个C++包装器,并从现有的GMP C++包装器(称为mpz_class)中获取灵感.当处理带有符号整数的mpz_t时,有如下代码:

static void eval(mpz_ptr z, signed long int l, mpz_srcptr w)
{
  if (l >= 0)
    mpz_add_ui(z, w, l);
  else
    mpz_sub_ui(z, w, -l);
}
Run Code Online (Sandbox Code Playgroud)

换句话说,如果有符号整数是正数,则使用无符号加法例程添加它,如果有符号整数为负,则使用无符号减法例程添加它.两个*_ui例程都将unsigned long作为最后一个参数.是表达

-l
Run Code Online (Sandbox Code Playgroud)

有溢出的危险吗?

Rol*_*lig 10

如果要避免溢出,首先应该n转换为unsigned int,然后将一元减号应用于它.

unsigned abs(int n) {
  if (n >= 0)
    return n;
  return -((unsigned)n);
}
Run Code Online (Sandbox Code Playgroud)

在原始代码中,否定在类型转换之前发生,因此如果行为是未定义的n < -INT_MAX.

当否定无符号表达式时,永远不会有溢出.相反,结果将是模数2^x,对于适当的值x.

  • 不,不.它适用于符合ISO C90或ISO C99的任何环境,这些标准都不需要两个补码算法.诀窍是通过在无符号算术中完全计算有趣的情况来避免对负整数的任何依赖. (2认同)
  • 好吧,现在我也得到了负部分,引用了C++标准:"无符号数量的负数是通过从2**n减去其值来计算的,其中n是提升操作数中的位数". (2认同)
  • 显然是这样,至少在C++(4.7.2)中:"如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模2**n,其中n是用于表示的位数)无符号类型)". (2认同)