对 unsigned int 进行一元运算的编译器警告

Posted

技术标签:

【中文标题】对 unsigned int 进行一元运算的编译器警告【英文标题】:Compiler warning for unary operation on 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 不应该在没有任何警告的情况下编译这段代码吗?

【问题讨论】:

【参考方案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)。

【讨论】:

以上是关于对 unsigned int 进行一元运算的编译器警告的主要内容,如果未能解决你的问题,请参考以下文章

C语言中,64位无符号整型如何进行开方运算?

为啥 F# 有一个一元加号运算符?

在 c语言中int long unsigned 和 char这四种类型数据的转换规律是_____.

c语言中 int unsigned 类型转换

JavaScript连载7-一元运算符赋值运算符逻辑运算符

关于C语言中unsigned变量的问题?