现在的位置: 首页 > 综合 > 正文

C++操作符的优先级

2019年02月07日 ⁄ 综合 ⁄ 共 4989字 ⁄ 字号 评论关闭


C++操作符的优先级

操作符及其结合性

功能

用法

L
L
L
::
::
::
全局作用域 
类作用域 
名字空间作用域
::name
class::name
namespace::name
L
L
L
L
L
.
->
[]
()
()
成员选择 
成员选择 
下标 
函数调用 
类型构造 
object.member
pointer->member
variable[expr]
name(expr_list)
type(expr_list)
R
R
R
R
R
++
--
typeid
typeid
显示强制类型转换 
后自增操作 
后自减操作 
类型ID
运行时类型ID
类型转换 
lvalue++
lvalue--
typeid(type)
typeid(expr)
cast_name<type>(expr)
R
R
R
R
R
R
R
R
R
R
R
R
R
R
sizeof
sizeof
++
--
~
!
-
+
*
&
()
new
delete
delete[]
对象的大小 
类型的大小 
前自增操作 
前自减操作 
位求反 
逻辑非 
一元负号 
一元正号 
解引用 
取地址 
类型转换 
创建对象 
释放对象 
释放数组
sizeof expr
sizeof(type)
++lvalue
--lvalue
~expr
!expr
-expr
+expr
*expr
&expr
(type)expr
new type
delete expr
delete []expr
L
L
->*
.*
指向成员操作的指针 
指向成员操作的指针
ptr->*ptr_to_member
obj.*ptr_to_member
L
L
L
*
/
%
乘法 
除法 
求模(求余)
expr * expr
expr / expr
expr % expr
L
L
+
-
加法 
减法
expr + expr
expr - expr
L
L
<< 
>>
位左移 
位右移
expr << expr
expr >> expr
L
L
L
L

<=

>=
小于 
小于或等于 
大于 
大于或等于
expr < expr
expr <= expr
expr > expr
expr >= expr
L
R
==
!=
相等 
不等
Expr == expr
Expr != expr
R & 位与 Expr & expr
R ^ 位异或 Expr ^ expr
R | 位或 Expr | expr
R && 逻辑与 Expr && expr
R || 逻辑或 Expr || expr
R ?: 条件操作 Expr ? expr : expr
R
R
R
R
R
=
*=,/=,%=
+=,-=
<<=,>>=
&=,|=,^=
赋值操作 
符合赋值操作 

Lvalue= expr
Lvalue+= expr
…… 

R throw 抛出异常 Throw expr
L , 逗号 Expr, expr
记忆方法:
--摘自《C语言程序设计实用问答》     -吕凤翥     吕     涛著   
    问题:如何记住运算符的15种优先级和结合性?   
    解答:C语言中运算符种类比较繁多,优先级有15种,结合性有两种。   
    如何记忆两种结合性和15种优先级?下面讲述一种记忆方法。   
    结合性有两种,一种是自左至右,另一种是自右至左,大部分运算符的结合性是自左至右,只有单目运算符、三目运算符的赋值运算符的结合性自右至左。   
    优先级有15种。记忆方法如下:   
    记住一个最高的:构造类型的元素或成员以及小括号。   
    记住一个最低的:逗号运算符。   
    剩余的是一、二、三、赋值。   
    意思是单目、双目、三目和赋值运算符。   
    在诸多运算符中,又分为:   
    算术、关系、逻辑。   
    两种位操作运算符中,移位运算符在算术运算符后边,逻辑位运算符在逻辑运算符的前面。再细分如下:   
    算术运算符分     *,/,%高于+,-。   
    关系运算符中,》,》=,《,〈=高于==,!=。   
    逻辑运算符中,除了逻辑求反(!)是单目外,逻辑与(&&)高于逻辑或(||)。   
    逻辑位运算符中,除了逻辑按位求反(~)外,按位与(&)高于按位半加(^),高于按位或(|)。   
    这样就将15种优先级都记住了,再将记忆方法总结如下:   
    去掉一个最高的,去掉一个最低的,剩下的是一、二、三、赋值。双目运算符中,顺序为算术、关系和逻辑,移位和逻辑位插入其中。   

为什么后缀++比*操作符优先级高却后对p加1?” ——*p++、*++p、++*p和(*p)++中的操作符优先级问题
假设 
int a[10] 
p1=a; 

那么 
*p++=1; 
*++p=2; 
++*p=3; 
(*p)++=4; 

分别应该怎么按照优先级别运算? 
按照书上的说法++ (后置) >++(前置) >* 解引用用 > = 等于 
*p++ 是否应该是 现算(p++) 在算* 最后 赋值? 
求所有的正确的算法 和解答 
--------------------------------------------------------------- 

++(后缀)属于“后缀操作符”,其优先级高于“前缀操作符”。 
* 和++(前缀)都属于“前缀操作符”,优先级相同,按从左到右结合的顺序。都高于赋值运算符。 

所以: 
*p++=1 相当于 (*(p++)) = 1,也就是说++操作于p上,结果为p原来的值,再作*运算,去除引用,再赋为1。总的作用就是把p引用的对象赋值为1,并把p加1。 

*++p=2 相当于(*(++p)) = 2,也就是说++操作于p上,结果为p加1后的值,再作*运算,去除引用,再赋值为1。总的作用就是把p加1,然后对其引用的对象赋值为2。 

++*p=3 相当于(++(*p)) = 3,也就是说先对p作*运算去除引用,其结果为p引用的对象,再把这个对象+1,结果还是这个对象,再把它赋值为3。这个表达式要求对象的前缀++操作符的返回值为左值。 

(*p)++=4 这里有一个强制优等级(括号),它的级别最高,结果就是((*p)++) = 4,也就是先对p作*运算去除引用,其结果为它引用的对 象,然后对这个对象作后缀++操作符,结果为这个对象操作前的值(一般是一个临时变量),然后把它赋值为4,这个表达式要求对象的后缀++操作符的返回值 为左值(整数类型是不符合要求的,只对定义了这个操作符的对象类型才有可能符合要求)。 

这个问题以C中很难试验出来,在C++中可以用操作符重载的方法看清楚(操作符重载不会改变优先级): 

#include <iostream> 

class test 

public: 
  test(){} 
  test(int){} 
  test& operator = (const test&){std::cout<<"Assignment of test" << std::endl; return *this;} 
  test& operator ++ (){std::cout << "Prefix ++ of test" << std:: endl; return * this;} 
  test& operator ++ (int) {std::cout << "Suffix ++ of test" << std::endl; return *this;} 
}; 
class testptr 

  test Value; 
public: 
  testptr& operator = (const test&){std::cout<<"Assignment of testptr" << std::endl; return *this;} 
  testptr& operator ++ (){std::cout << "Prefix ++ of testptr" << std:: endl; return * this;} 
  testptr& operator ++ (int) {std::cout << "Suffix ++ of testptr" << std::endl; return *this;} 
  test& operator *(){std::cout<< "Operator * of testptr"<<std::endl; return Value;} 
}; 

#define TRACK(X) std::cout <<std::endl<<"*****  "<< #X << " *****" <<std::endl; X 
int main() 

    testptr p; 
    TRACK(*p++=1); 
    TRACK(*++p=2); 
    TRACK(++*p=3); 
    TRACK((*p)++=4); 
    std::cin.get(); 

输出为 
*****  *p++=1 ***** 
Suffix ++ of testptr 
Operator * of testptr 
Assignment of test 

*****  *++p=2 ***** 
Prefix ++ of testptr 
Operator * of testptr 
Assignment of test 

*****  ++*p=3 ***** 
Operator * of testptr 
Prefix ++ of test 
Assignment of test 

*****  (*p)++=4 ***** 
Operator * of testptr 
Suffix ++ of test 
Assignment of test 

int p = 1; 
int a = p++; 
结果a=1,并不是因为后缀++优先级低(我记得有一本C教材就是这样写的,真是误人子弟),而是由后缀++的语义决定的。标准的后缀++应该是 “对操作对象做+1操作,并返回操作前的值”,它在赋值运算前运算了,但它的返回值并不是p,而是p在做+1运算前的值。因此我们还可以知道,p++的返 回值应该不是一个左值,p++=a是无法编译通过的。而前缀++则不一样,++p的含义就是“对p做+1运算,并返回p”,其返回值就是p本身(引用), 是一个左值,++p = a是可以编译的(但没什么意义)。 

如果用代码描述一下这两个操作符,应该是这样的: 

const int int::operator ++(int)//后缀++ 

  int temp = *this; 
  *this = *this +1; 
  return temp; 

int& int::operator ++()//前缀++ 

  *this = *this + 1; 
  return *this; 

补充: 
在C中,上述语句含义分别是: 
*p++=1; --> temp = p + 1; *temp = 1; 
*++p=2; --> p = p +1; * p = 1; 
++*p=3; --> *p = *p + 1; *p = 3; 
(*p)++=4;//语法错误,无法写出对应的语句。 

由于后缀增/减量操作符的特殊性,导致初学者很难理解“为什么后缀的++优先级高却后对变量加1呢?”事实上,事实上,“后缀++”并不是后对变 量加1,而是先做了,只是它的返回值并不是这个变量,而是这个变量改变前的值。如果对它很难理解,建议不要使用这几个操作符,而改用普通的加/减法操作 符: 
*p++=1; --> *p = 1; p = p + 1; 
*++p=2; --> p = p + 1; *p = 2; 
++*p=3; --> *p = *p + 1; *p = 3; 
(*p)++=4;//语法错误,无法写出对应的语句。 

由于在C++中这几个操作符不再是整数和指针类型特有的,而是可以为类定义的,并且它们可以和+/-1操作语义不同或根本没有加/减法操作符(如 双向迭代器),不能简单地用加/减法代替。不过C++程序员们可以通过看比较好的类的操作符重载函数(如迭代器的)代码真正明白后缀增/减量操作符的语 义,不会因为它“优先级高却后对变量加1”的问题糊涂。不过,仅管如此,我还是认为使用增/减量操作符时最好让一个表达式中或者没有增/减量操作符,或者 只有一个增/减量操作符,如:++p;*p = 1;(相当于*++p = 1)或*p = 1;++p;(相当于*p++=1),这样也不用去区分前缀
和后缀的区别了。 

抱歉!评论已关闭.