【问题标题】:Compiler warning for unary operation on unsigned int对 unsigned int 进行一元运算的编译器警告
【发布时间】:2010-11-24 13:18:16
【问题描述】:

我有这个示例代码,它会生成以下警告(带有 SP1 的 VS2008 编译器):

警告 C4146:一元减号运算符 应用于无符号类型,结果仍然 未签名

代码:

void f(int n)
{
}

int main()
{
    unsigned int n1 = 9;
    f(-n1);
}

但是由于函数 f 将其参数作为 int 不应该在没有任何警告的情况下编译这段代码吗?

【问题讨论】:

    标签: c++ compiler-warnings unsigned


    【解决方案1】:

    如果xunsigned int 类型,那么-x 也是如此,它实际上等同于2<sup>n</sup>-x(其中n 很可能是32)。为避免警告获得正确的行为,请转换为int

    f(-static_cast<int>(n));
    

    我建议阅读 C++ 标准的“表达式”一章。在那里你会看到在-x 表达式中,积分提升发生在x,这意味着几乎任何东西都被提升为int,但unsigned int 不是。

    看看这个非常有趣的例子:

    template<class T>
    void f(T x)
    {
      //somehow print type info about x, e.g. cout << typeid(x).name() or something
    }
    
    int main()
    {
      char x;
      f(x);
      f(+x);
      f(-x);
    }
    

    打印:

    char
    int 
    int
    

    但是char -> int 是整体提升,而unsigned int -> int 是转换

    【讨论】:

    • 请参阅@Andreas 对促销的报价和定义的回答 :)
    • 这适用于值“9”,但我认为一般(int)(-(unsigned)x)-(int)x并不完全相同,因为如果x是INT_MIN,应用减号是一个未定义的溢出,而对于所有无符号值,无符号值的一元减号是明确定义的。不过,如果我错了,请纠正我。
    【解决方案2】:

    标准 5.3.1/7

    一元 - 运算符的操作数 应有算术或枚举 类型,结果是否定的 它的操作数。整体推广是 在积分或枚举上执行 操作数。无符号的负数 数量是通过减去来计算的 它的值来自 2n,其中 n 是 提升的位数 操作数。结果的类型是 提升操作数的类型。

    还有关于 Integral Promotion 4.5/1 的段落

    char 类型的右值,带符号的 char, unsigned char、short int 或 unsigned short int 可以转换为 如果 int 可以,则为 int 类型的右值 表示源的所有值 类型;否则,源右值可以 被转换为类型的右值 无符号整数。

    即unsigned int 不会被提升为 int。

    【讨论】:

      【解决方案3】:

      参数是按值传递的。在函数调用 f(-n1) 中,在将参数传递给函数之前应用运算符。因此发出警告。

      【讨论】:

        【解决方案4】:

        编译器警告您,将一元减号应用于 unsigned int 是一件不寻常的事情,并且可能不会给出您期望的结果。如果您使用的是 32 位编译器,在这种情况下得到的结果将等同于调用 f(4294967287u)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-07-20
          • 2011-05-09
          • 1970-01-01
          • 2023-03-14
          • 1970-01-01
          相关资源
          最近更新 更多