对 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】:如果x
是unsigned 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 进行一元运算的编译器警告的主要内容,如果未能解决你的问题,请参考以下文章