Re: [問題] 同一行程式碼變更變數兩次

看板C_and_CPP作者 (purpose)時間15年前 (2010/10/13 18:11), 編輯推噓4(4032)
留言36則, 7人參與, 最新討論串2/2 (看更多)
: sum = sub_Function_a ( max ) + sub_Function_b ( max++ ); 借這篇文章,提出我對「Sequence Point」一直以來的疑問,真心跪求知識帝解惑。 之前看這篇文章:http://en.wikipedia.org/wiki/Sequence_point 裡面提到在 C/C++ 的 Sequence Point (順序點) 中,有一個順序點是 「Before a function is entered in a function call.」 在微軟 MSDN 的文章中:http://msdn.microsoft.com/en-us/library/d45c7a5d.aspx 亦指出函數呼叫本身是個順序點。 「Function-call operator. The function-call expression and all arguments to a function, including default arguments, are evaluated and all side effects completed prior to entry to the function.」 又「相加運算子+」的運算優先權高於「指派運算子=」,所以只剩下決定,要先呼叫 sub_Function_a(max) 還是先呼叫 sub_Function_b(max++)。誰先被呼叫,對於結果當然 是有差別的。 但我以為這個部份應該不是未定義的,應該一定是先呼叫 sub_Function_a(max) 吧? 因為看這篇:http://msdn.microsoft.com/en-us/library/yck2zaey.aspx 講解運算優先順序。 該文的圖1 舉「cout << a+b*c << "\n";」做為解說例子。 當 a+b*c 的運算做完,假設是 5566 好了,其運算就變成「cout << 5566 << "\n";」 然後該文章說 「Left shift (<<) has the lowest precedence in the expression, but there are two occurrences. Because the left-shift operator groups left-to-right, the left subexpression is evaluated first and then the right one.」 因為 << 這個二元運算子是左結合性,所以先執行「cout << 5566」,那原文的 sub_Function_a ( max ) + sub_Function_b ( max++ ) 運算,其中 function call 運算子的優先權最高,一定要先執行函數呼叫。又 function call 在 MSDN 也是寫他 結合性為由左到右:http://msdn.microsoft.com/en-us/library/126fe14k.aspx 所以我才認為,應該 sub_Function_a(max) 會先執行,而不是未定義, 但 gcc 是會給警告訊息,而且 wiki 的網頁裡面也說,函數執行順序不一定 「However, it is not specified in which order f(), g(), h() are executed.」 有修過編譯器的課程,但是沒吸收到多少, 求解惑,感謝。 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 124.8.128.171

10/13 18:14, , 1F
不知道 max先加一呢? 或是先呼叫 sub function?
10/13 18:14, 1F

10/13 18:15, , 2F
雖然以下講法很不求長進, 但應該可以把時間花在更值得的
10/13 18:15, 2F

10/13 18:15, , 3F
事物上.
10/13 18:15, 3F

10/13 18:16, , 4F
寫程式寫出來就是要確保那段程式是可以重覆被利用的, 而
10/13 18:16, 4F

10/13 18:17, , 5F
且是依照使用者下達的指令/意圖去完成想要的結果.
10/13 18:17, 5F

10/13 18:18, , 6F
可是偏偏這個例子只是想省去一行程式碼(我目光淺薄只看
10/13 18:18, 6F

10/13 18:19, , 7F
到這點), 卻不用更好閱讀更好理解程式的寫法去分別處理
10/13 18:19, 7F

10/13 18:19, , 8F
這兩次呼叫 sub function.
10/13 18:19, 8F

10/13 18:20, , 9F
要自虐, 要考驗compiler的能力也就算了.
10/13 18:20, 9F

10/13 18:21, , 10F
嗯,會先把max送進堆疊,再把max做++,再呼叫sub function
10/13 18:21, 10F

10/13 18:21, , 11F
以保證,所有副作用會在進入函數主題前發生完成。
10/13 18:21, 11F

10/13 18:21, , 12F
函數「主體」(body)
10/13 18:21, 12F

10/13 18:23, , 13F
很常見的寫法是 result = foo(a) + bar(b); 如果 a,b 是
10/13 18:23, 13F

10/13 18:23, , 14F
全域變數,那在 foo 時看得到 b,此時就非得考慮 bar 是否
10/13 18:23, 14F

10/13 18:24, , 15F
在 foo 之前有對 a,b 做過改變
10/13 18:24, 15F

10/13 18:38, , 16F
結合順序是多個相加才要討論 你這只有一個加號而已
10/13 18:38, 16F

10/13 18:39, , 17F
與實作相關的部分是哪個先呼叫 不是多個加號時要怎樣結合
10/13 18:39, 17F

10/13 18:43, , 18F
就算是左結合, 畫遞迴樹出來看, 它們還在同一個LEVEL
10/13 18:43, 18F

10/13 18:47, , 19F
↑parsing tree
10/13 18:47, 19F

10/13 18:57, , 20F
>10/13 18:38 可是有兩個()運算子,而()運算子也是左結合
10/13 18:57, 20F

10/13 18:58, , 21F
遞迴樹我不會,以後有機會看看,謝謝
10/13 18:58, 21F

10/13 19:07, , 22F
但()本身已經有限制求值順序的功能 它是兩個 token
10/13 19:07, 22F

10/13 19:08, , 23F
就算不看parse tree也知道在這裡兩個誰先做並沒有一定
10/13 19:08, 23F

10/13 19:08, , 24F
所以這裡一直都沒有結合性問題
10/13 19:08, 24F

10/13 19:09, , 25F
這裡的兩個()就像(3+4)*(5+6)一樣 3+4和5+6誰先算並沒有一定
10/13 19:09, 25F

10/13 19:10, , 26F
即使(3+4)*(5+6)*(7+8)也一樣 雖然第一個*先算
10/13 19:10, 26F

10/13 19:10, , 27F
但並沒有規定7+8就得在*算完之後才能算
10/13 19:10, 27F

10/13 19:17, , 28F
謝謝 LPH66 前輩回答,對我很有幫助,感激不盡。
10/13 19:17, 28F

10/13 19:36, , 29F
簡單說就是「評估值」跟「計算」的順序是兩碼子事
10/13 19:36, 29F

10/13 19:40, , 30F
左結合是說如果a+b+c就一定要先求a+b再求c
10/13 19:40, 30F

10/13 19:41, , 31F
但是並不代表任何x+y都一定是先去取x值.
10/13 19:41, 31F

10/13 19:41, , 32F
這觀念當初也是受lph66指點過才稍微記得.
10/13 19:41, 32F

10/13 21:16, , 33F
我倒是覺得你編譯器修到 100 分,也未必有學到這東西。
10/13 21:16, 33F

10/13 21:17, , 34F
因為這種東西,實質上不算在 compiler 的課程範圍內。
10/13 21:17, 34F

10/13 22:16, , 35F
謝謝各位版友的回應,我以後會好好做人。
10/13 22:16, 35F

10/13 22:16, , 36F
編譯器我沒買書,學分又是混到的,所以才有此誤解,謝指正
10/13 22:16, 36F
文章代碼(AID): #1CjOMsdd (C_and_CPP)
文章代碼(AID): #1CjOMsdd (C_and_CPP)