[英]Understanding evaluation of expressions containing '++' and '->' operators in C
考慮這個例子:
struct {
int num;
} s, *ps;
s.num = 0;
ps = &s;
++ps->num;
printf("%d", s.num); /* Prints 1 */
它打印1
。
所以我理解這是因為根據運算符優先級, ->
高於++
,所以首先獲取值ps->num
(即0),然后++
運算符對其進行操作,因此它將其遞增為1。
struct {
int num;
} s, *ps;
s.num = 0;
ps = &s;
ps++->num;
printf("%d", s.num); /* Prints 0 */
在這個例子中,我得到0
,我不明白為什么; 對於這個例子,第一個例子的解釋應該是相同的。 但似乎這個表達式的評估如下:
首先,運算符++
運行,並且它在ps
運行,因此它將它遞增到下一個struct
。 只有這樣->
運行並且它什么都不做,因為它只是獲取下一個struct
的num
字段struct
做任何事情。
但它與運算符的優先級相矛盾,后者表示->
具有比++
更高的優先級。
有人可以解釋這種行為嗎?
編輯 :
在閱讀了兩個引用C ++優先級表的答案后,表示前綴++
/ --
運算符的優先級低於->
,我做了一些谷歌搜索,並提出了這個鏈接 ,表明此規則也適用於C本身。 它恰好完全解釋了這種行為,但我必須補充一點,這個鏈接中的表與我自己的K&R ANSI C副本中的表相矛盾。所以如果你有關於哪個源是正確的建議我想知道。
謝謝。
后增量( ps++
)和預增量( ++ps
)在C中具有不同的關聯性。前者從左到右關聯,而后者從右到左關聯。 檢查此頁面(雖然這是針對C ++的,因此優先級可能會產生誤導)。
在上一個示例中,您將指針更改為超過&s
結尾的指針。 您沒有更改指針的值。 如果需要增加num
,則需要將++
綁定到num
。
詳細說明:
ps++->num;
看到這個表達式的(假設的)編譯器可以將ps
對象推送到堆棧,然后是++
運算符, ->
運算符,最后是object - num
。 在評估時,編譯器應該從哪里開始? 它查看可用的運算符,即++
和->
。 它選擇ps++
還是ps
? 這里是優先規則:因為->
的優先級高於++
,所以需要->
將num
作為一個操作數進行處理,將ps
作為另一個操作數進行處理。 因此,正確觀察時,表達式的值變為ps->num
即0。 評估后ps
會發生什么? 請記住,堆棧上還有另一個操作員? 因此,編譯器將此應用於ps
,它現在指向一個元素過去&s
。
腳注:
ANSI / ISO C標准不使用運算符優先級語法。 相反,它使用所謂的完全因子語法。 這通常涉及嚴格的語法定義,其中點綴有許多非終端,如“primary-expression”和“shift-expression”等。 這很難理解,但對語言設計者或編譯器供應商來說更容易理解。 而且,這樣的語法能夠容易地編碼優先級。 但是,任何完全分解的語法都與運算符優先級語法兼容,這是大多數書籍(和網站)所做的(有時也會搞亂)。
即使++具有更高的優先級,這也不會改變值 - >操作,因為它是后增量。 請參閱此代碼,其中還包含此行為的另一個示例:
int b = 5;
int a = b++ * 3;
b = 5;
int c = (b++) * 3;
printf("%i, %i, %i\n", a, b, c); // Prints 15, 6, 15
struct {
int num;
} s, *ps;
s.num = 35;
ps = &s;
printf("%p\n", ps); // Prints the pointer
printf("%i\n", ps++->num); // Prints 35
printf("%p\n", ps); // Prints the increased pointer
printf("%d\n", s.num); /* Prints 35 */
b = ++ a; 相當於:
a += 1;
b = a;
b = a ++; 相當於:
b = a;
a += 1;
所以很明顯為什么你沒有得到你想要的結果。 你描述的東西相當於(++ ps) - > num。
“優先權”基本上是衍生財產; 它來自解析規則。 ++ ps-> num被解析為++(ps-> num)/ *(),用於澄清解析規則* /而ps ++ - > num只能解析為(ps ++) - > num。
我想這是因為它們具有不同的優先級,並且在同一組中,它們具有特定的關聯性(例如,評估順序)
點擊這里 后綴運算符與指針解析具有相同的優先級,但前綴運算符的優先級較低。
ps ++ - > num將指針ps遞增1,然后讀取其中的數據。 因為ps就在堆棧上的s之后,我相信指針很可能指向自己,雖然我不確定,但並不重要。 基本上初始程序正在做++(ps-> num)但沒有括號。 要實現同樣的目的,但在訪問數據之后,您必須執行(ps-> num)++,或者不使用括號:ps-> num ++。
因為ps只是一個指針,即使你改變它的值,s仍然保持不變。
優先級用於解決模糊解析。 ++ps->num
可以解析為((++ps)->num)
或(++(ps->num))
; ++()
和->
的相對優先級確定后者是正確的解析。
對於ps++->num
,只有一個有效的解析: ((ps++)->num)
,因此運算符的優先級無關緊要。
在這里您可以看到++作為前綴的優先級低於 - >,但作為后綴,它具有與 - >相同的優先級,並且從左到右進行評估,因此首先完成ps ++,然后是 - >。
編輯:這是針對C ++,而不是C.所以我的答案是不正確的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.