我有这个示例代码生成以下警告(带SP1的VS2008编译器):
警告C4146:一元减运算符 应用于无符号类型,结果仍然存在 无符号
代码:
void f(int n)
{
}
int main()
{
unsigned int n1 = 9;
f(-n1);
}
但是因为函数f
将它的参数作为int
而不应该编译而没有任何警告?
答案 0 :(得分:15)
如果x
属于unsigned int
类型,则-x
也是如此,它实际上等同于2n-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
- &gt; unsigned int
是不可或缺的促销,而int
- &gt; {{1}}是转化
答案 1 :(得分:12)
标准5.3.1 / 7
一元运算符的操作数 应有算术或枚举 类型,结果是否定 它的操作数。整体推广是 在积分或枚举上执行 操作数。无符号的否定 数量通过减去来计算 它的值来自2n,其中n是 升级中的位数 操作数。结果的类型是 提升操作数的类型。
关于积分推广4.5 / 1的段落
char类型的rvalue,signed char, unsigned char,short int或unsigned short int可以转换为 如果int可以,则为int类型的rvalue 表示源的所有值 类型;否则,源rvalue可以 转换为类型的右值 unsigned int。
即。 unsigned int不会被提升为int。
答案 2 :(得分:2)
参数是按值传递的。在函数调用f(-n1)中,在将参数传递给函数之前应用运算符。因此警告。
答案 3 :(得分:0)
编译器警告你将unary减号应用于unsigned int是一件不寻常的事情,可能无法给出你期望的结果。如果您使用的是32位编译器,那么在这种情况下得到的结果将等同于调用f(4294967287u)。