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),這樣也不用去區分前綴和后綴的區別了。
轉自:
http://blog.163.com/wjh2-316/blog/static/2787275320086810153137/