Mic*_*ael 72 c++ arithmetic-expressions
我的程序中有一个奇怪的错误,经过几个小时的调试后,我发现了以下非常愚蠢的行:
int a = b * (c * d * + e)
Run Code Online (Sandbox Code Playgroud)
如果你没有看到它:在d和e我之间写的* +,只是一个+意图.
为什么这会编译,它实际上意味着什么?
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)
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)它有以下评论:
一元加上是一次历史性事故,一般都没用.
正如他们所解释的那样,(+)和( - )只是用作一元运算符:
一元运算符仅对表达式中的一个操作数起作用
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)
为什么会编译?它可以编译,因为+被解析为一元加运算符,而不是加运算符。编译器尝试尽可能多地解析而不产生语法错误。所以这:
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 次 |
| 最近记录: |