我的程序出了一个奇怪的错误,在调试了几个小时后,我发现以下这一行非常愚蠢:
int a = b * (c * d * + e)
如果您没有看到它:在d
和e
之间,我写了* +
,实际上只想写一个+
。为什么这可以编译通过,并且它实际上表示什么?
我的程序出了一个奇怪的错误,在调试了几个小时后,我发现以下这一行非常愚蠢:
int a = b * (c * d * + e)
如果您没有看到它:在d
和e
之间,我写了* +
,实际上只想写一个+
。+
被解释为一元加法操作符。它只是简单地返回其操作数的提升值。
int a = b * (c * d * (+e))
完全相同的效果。 - Cort Ammon一元运算符+
返回提升后的值。
一元运算符-
返回取反:
int a = 5;
int b = 6;
unsigned int c = 3;
std::cout << (a * +b); // = 30
std::cout << (a * -b); // = -30
std::cout << (1 * -c); // = 4294967293 (2^32 - 3)
-
符号也不一定返回“负数值”: int b = -5; std::cout << -b;
- MSalters+
被解释为一元加号,对于整数或枚举类型会执行整型提升操作,结果将具有提升操作数的类型。假设e
是整数或未作用域的枚举类型,则由于*
应用其操作数的通常算术转换,最终会进行整型提升。从C++标准草案中可以看到,在[expr.unary.op]第5.3.1节中:整型提升在[conv.prom]第4.5节中有所涵盖,如果变量一元加运算符的操作数必须具有算术、未作用域的枚举或指针类型,结果是参数的值。对于整数或枚举操作数进行整型提升。结果的类型是提升操作数的类型。
e
的类型不是bool、char16_t、char32_t
或wchar_t
,并且其转换级别小于int,则它将被第1段所涵盖。-
和负值的答案,这是具有误导性的,正如这个例子所示:#include <iostream>
int main()
{
unsigned x1 = 1 ;
std::cout << -x1 << std::endl ;
}
4294967295
请查看实时演示 使用wandbox上的gcc。
有趣的是,C99添加了一元加号以与一元减号对称,来自于国际标准编程语言C的缘由:
一元加号被C89委员会从多个实现中采用,以与一元减号对称。
我无法想出一个好的情况,其中强制转换不足以实现相同的所需升级/转换。我引用上面的lambda示例,使用一元加号将lambda表达式强制转换为函数指针:
foo( +[](){} ); // not ambiguous (calls the function pointer overload)
foo( static_cast<void (*)()>( [](){} ) );
可以说,这段代码更好,因为意图是明确的。
值得注意的是,带注释的C++参考手册(ARM)中有以下评论:
一元加号是历史遗留问题,通常没有用。
他们所解释的,(+)和(-)只是作为一元运算符使用:
一元运算符仅对表达式中的一个操作数起作用。
int value = 6;
int negativeInt = -5;
int positiveInt = +5;
cout << (value * negativeInt); // 6 * -5 = -30
cout << (value * positiveInt); // 6 * +5 = 30
cout << (value * - negativeInt); // 6 * -(-5) = 30
cout << (value * + negativeInt); // 6 * +(-5) = -30
cout << (value * - positiveInt); // 6 * -(+5) = -30
cout << (value * + positiveInt); // 6 * +(+5) = 30
所以根据您的代码:
int b = 2;
int c = 3;
int d = 4;
int e = 5;
int a = b * (c * d * + e)
//result: 2 * (3 * 4 * (+5) ) = 120
+
被解析为一元加运算符而不是加法运算符。编译器在尽可能多地解析语法而不产生错误的情况下进行编译。因此,以下代码可以成功编译:d * + e
被解析为:
d
(操作数)*
(乘法运算符)+
(一元正号运算符)
e
(操作数)而这段代码:
d*++e;
被解析为:
d
(操作数)*
(乘法运算符)++
(前置自增运算符)
e
(操作数)此外,下面的内容也需要翻译:
d*+++e;
被解析为:
d
(操作数)*
(乘法运算符)++
(前缀自增运算符)
+
(一元正号运算符)
e
(操作数)请注意,它不会创建语法错误,但会出现“需要LValue”的编译器错误。
在这里提供了正确答案后,再加上一些内容,如果你使用-s标志编译,C编译器将会输出一个汇编文件,可以查看生成的指令。以下是C代码:
int b=1, c=2, d=3, e=4;
int a = b * (c * d * + e);
movl $1, -20(%ebp)
movl $2, -16(%ebp)
movl $3, -12(%ebp)
movl $4, -8(%ebp)
因此,我们可以将-20(%ebp)标识为变量 b,将-8(%ebp)标识为变量 e,将-4(%epp)标识为变量 a。现在,计算公式如下:
movl -16(%ebp), %eax
imull -12(%ebp), %eax
imull -8(%ebp), %eax
imull -20(%ebp), %eax
movl %eax, -4(%ebp)
5 * -4 = -20
5 * +4 = 5 * 4 = 20
-5 * -4 = 20
负数 * 负数 = 正数
正数 * 负数 = 负数
正数 * 正数 = 正数
这是最简单的解释。
减号(-)和加号(+)只是表示数值是正数还是负数。
int a = -5; int val = -a; //结果 val: 5
- Dyrandz Famadorint a = b*(c*d*e) ;
std::cout << +c;
如果这种情况经常发生,那么static_cast
会变得非常混乱。 - chris2 × (3 × 4 × +5)
是什么意思? - Jon HannaC
,而且由于这个问题已经有了C++特定的答案,我们不应该改变这个标签。 - Shafik Yaghmour