编译器在这里做了什么:int a = b*(c*d*+ e)?

Mic*_*ael 72 c++ arithmetic-expressions

我的程序中有一个奇怪的错误,经过几个小时的调试后,我发现了以下非常愚蠢的行:

int a = b * (c * d *  + e)
Run Code Online (Sandbox Code Playgroud)

如果你没有看到它:在de我之间写的* +,只是一个+意图.

为什么这会编译,它实际上意味着什么?

Bri*_*ian 116

+被解释为一个一元加运算符.它只返回其操作数的提升值.

  • 有关"升级"的详细信息,[请参阅此处](http://stackoverflow.com/a/24805967/1505939) (13认同)
  • 其效果与`int a = b*(c*d*(+ e))`相同 (6认同)

And*_* DM 27

一元+返回提升的值.
一元-回归否定:

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)
Run Code Online (Sandbox Code Playgroud)

  • "正面价值"具有误导性.这听起来像是返回操作数的绝对值,但实际情况并非如此. (32认同)
  • `-`也不一定返回"负值":`int b = -5; std :: cout << -b;` (8认同)

Sha*_*our 18

+是因为它被解释为一元加号,它将对积分或枚举类型执行整数提升,结果将具有提升操作数的类型.

假设e是一个整数或无范围的枚举类型,最终将应用整数促销,因为*通常的算术转换应用于其操作数,最终为整数类型的整体促销.

从草案C++标准5.3.1 [expr.unary.op]:

一元+运算符的操作数应具有算术,无范围枚举或指针类型,结果是参数的值.对整数或枚举操作数执行整体提升.结果的类型是提升的操作数的类型.

整数促销在4.5 [conv.prom]部分中介绍,如果变量e是非类型bool, char16_t, char32_t, or wchar_t且转换等级小于int的类型,那么它将被段落覆盖1:

如果int可以表示源类型的所有值,则除了bool,char16_t,char32_t或wchar_t之外的整数类型的prvalue(其整数转换等级(4.13)小于int的等级)可以转换为int类型的prvalue ; 否则,源prvalue可以转换为unsigned int类型的prvalue.

对于一整套案例,我们可以查看cppreference.

在一些情况下,一元加号也可以用来解决歧义,一个有趣的例子是解决函数指针上的模糊重载和使用+的lambda的std :: function.

请注意,对于那些答案,指的是一元-和负值,这是误导性的,如下例所示:

#include <iostream>

int main()
{
    unsigned  x1 = 1 ;

    std::cout <<  -x1 << std::endl ;
}
Run Code Online (Sandbox Code Playgroud)

这导致:

4294967295
Run Code Online (Sandbox Code Playgroud)

在wandbox上使用gcc实时查看.

值得注意的是,从国际标准程序设计语言的基本原理C中,将一元加号添加到C99中以确定对称性与一元减号:

C89委员会从几个实施中采用了一元加,用于对称与一元减.

而且我无法想出一个好的案例,即铸造不足以实现同样的理想促销/转换.我在上面引用的lambda示例,使用一元加号强制将lambda表达式转换为函数指针:

foo( +[](){} ); // not ambiguous (calls the function pointer overload)
Run Code Online (Sandbox Code Playgroud)

可以使用显式强制转换完成:

foo( static_cast<void (*)()>( [](){} ) );
Run Code Online (Sandbox Code Playgroud)

并且可以认为这个代码更好,因为意图是明确的.

值得注意的是Annotated C++ Reference Manual(ARM)它有以下评论:

一元加上是一次历史性事故,一般都没用.


Dyr*_*dor 9

正如他们所解释的那样,(+)和( - )只是用作一元运算符:

一元运算符仅对表达式中的一个操作数起作用

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
Run Code Online (Sandbox Code Playgroud)

所以从你的代码:

int b = 2;
int c = 3;
int d = 4;
int e = 5;

int a = b * (c * d *  + e)

//result: 2 * (3 * 4 * (+5) ) = 120
Run Code Online (Sandbox Code Playgroud)


Sal*_*n A 5

为什么会编译?它可以编译,因为+被解析为一元加运算符,而不是加运算符。编译器尝试尽可能多地解析而不产生语法错误。所以这:

d * + e
Run Code Online (Sandbox Code Playgroud)

解析为:

  • d(操作数)
  • *(乘法运算符)
  • +(一元加运算符)
    • e(操作数)

然而,这个:

d*++e;
Run Code Online (Sandbox Code Playgroud)

解析为:

  • d(操作数)
  • *(乘法运算符)
  • ++(预增量运算符)
    • e(操作数)

此外,这:

d*+++e;
Run Code Online (Sandbox Code Playgroud)

解析为:

  • d(操作数)
  • *(乘法运算符)
  • ++(预增量运算符)
    • +(一元加运算符)
      • e(操作数)

请注意,它不会创建语法错误,而是创建“LValue required”编译器错误。


归档时间:

查看次数:

7760 次

最近记录:

7 年,3 月 前