[問題] 執行順序

看板C_and_CPP (C/C++)作者 ( //StrategyBass)時間16年前 (2009/11/25 07:58), 編輯推噓34(34038)
留言72則, 14人參與, 最新討論串1/1
請問一下以下程式碼: printf("gg: %d %d %d\n", gg(),gg(),gg()); 3 <- 2 <- 1 是不是會先執行右邊的gg() 再執行中間的gg() 最後是左邊的gg() ? 我一直覺得這是某個原則,但是一直想不起來 感謝! -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 218.168.189.9

11/25 08:07, , 1F
我記得是依照compiler做法不同而不同
11/25 08:07, 1F

11/25 08:08, , 2F
這standard沒規定嗎?我的是gcc 4.3.4
11/25 08:08, 2F

11/25 09:18, , 3F
沒規定
11/25 09:18, 3F

11/25 09:23, , 4F
如果維基沒寫錯的話,第四點,沒有規定順序
11/25 09:23, 4F

11/25 09:23, , 5F
不過你的例子三個都是 gg(),順序應該也無所謂
11/25 09:23, 5F

11/25 09:28, , 6F
先右邊再往左邊,那除非像 a=b=c; assignment是右結合性
11/25 09:28, 6F

11/25 09:29, , 7F

11/25 09:55, , 8F
順序有差吧 如果gg()裡面有一個static counter
11/25 09:55, 8F

11/25 09:55, , 9F
那顯示出來的結果會很幽默的
11/25 09:55, 9F
M大厲害,這個問題確實是因為我在研究static變數而發現的 code出自於K&R2 若把三個gg()拆成各三個printf就不會發現這個現象...

11/25 10:29, , 10F
stack吧,push 左 中 右,pop 最上面的就是右邊最先執行
11/25 10:29, 10F

11/25 10:38, , 11F
應該不是這麼看的吧??樓上這樣看也少考慮了side effect
11/25 10:38, 11F

11/25 10:38, , 12F
的影響....@_@"
11/25 10:38, 12F

11/25 11:16, , 13F
嗯,M大說的對。本來是想說,既然三個都是gg(),則gg()
11/25 11:16, 13F

11/25 11:17, , 14F
一定有機會三種順序都體驗一遍,忽略了printf想要的結果
11/25 11:17, 14F

11/25 11:35, , 15F
應該沒差吧?..還不都是執行同一程序.....
11/25 11:35, 15F

11/25 11:38, , 16F
用C寫和Delphi寫應該都一樣...call conversion不同而已.
11/25 11:38, 16F

11/25 11:43, , 17F
或許還要看printf()是怎麼處理輸出的...
11/25 11:43, 17F

11/25 11:44, , 18F
calling convention不是標準的樣子,似乎跟硬體、OS有關
11/25 11:44, 18F

11/25 11:45, , 19F
先把傳回值通通放在同一個地方再一起輸出的話就沒差...
11/25 11:45, 19F

11/25 11:47, , 20F
calling convention不是影響的是function call時stack
11/25 11:47, 20F

11/25 11:48, , 21F
operation的機制嗎?? push/pop param的位置不同這樣@_@"
11/25 11:48, 21F

11/25 11:48, , 22F
看來應該還是看compiler怎麼編譯?......
11/25 11:48, 22F

11/25 11:49, , 23F
而且, 還是像M大說的, 有static counter或者有影響
11/25 11:49, 23F

11/25 11:50, , 24F
global counter時, 本例印的順序就會變成依compiler實
11/25 11:50, 24F

11/25 11:50, , 25F
作而不同@_@"
11/25 11:50, 25F

11/25 11:51, , 26F
http://tinyurl.com/ygun3or 這裡有外國人的討論
11/25 11:51, 26F

11/25 11:55, , 27F
所以結論是什麼?..@_@"越看越搞不清楚....
11/25 11:55, 27F

11/25 11:57, , 28F
中午拿這個配飯吃會不會比較不好消化....Orz
11/25 11:57, 28F

11/25 11:58, , 30F
我覺得跟這篇紅色的「Argument push order? 」意見一樣
11/25 11:58, 30F

11/25 11:58, , 31F
反正就是不要依賴次序,就分多個statement就好,急什麼
11/25 11:58, 31F

11/25 12:00, , 32F
evaluation order 和 calling convention 並無絕對關係
11/25 12:00, 32F

11/25 12:00, , 33F
即使第三個gg()的結果要先推進stack
11/25 12:00, 33F

11/25 12:01, , 34F
也不表示compiler第一個呼叫的是它
11/25 12:01, 34F

11/25 12:05, , 35F
先謝一下221大的callconv網站, 早點看到這個以前修bug時
11/25 12:05, 35F

11/25 12:05, , 36F
就可以少繞些遠路少碰些釘子了....Q_Q~
11/25 12:05, 36F
※ 編輯: ikari512 來自: 218.168.189.9 (11/25 12:49) 所以結論是:這是undefined behaviour,視compiler而定? 有什麼簡單的判斷方法可以避開這種事嗎 因為看起來不只是要小心 同一statement不要call同一函式(裡面可能有static變數) 連 int i=1; printf("%d %d %d", i++, i++, i++); 這種也會輸出 3 2 1 btw... 順便請教一個不太相關的printf問題 在什麼樣的情況下 printf("111"); printf("222"); 會先印出222? 記得這跟buffer大小有關係 但是什麼buffer、什麼情況我想不起來 而這會對debug產生干擾... thx... ※ 編輯: ikari512 來自: 218.168.189.9 (11/25 13:06)

11/25 13:08, , 37F
"printf("%d %d %d", i++, i++, i++);"這個code裡至少存
11/25 13:08, 37F

11/25 13:08, , 38F
在兩種undefined behavior, 一個就是function call時參
11/25 13:08, 38F

11/25 13:09, , 39F
數的evaluation order, 另一個是一個expression裡對同一
11/25 13:09, 39F

11/25 13:10, , 40F
變數做了三次給值, 這點應該置底十誡之九有提到....@_@"
11/25 13:10, 40F
了解...

11/25 13:13, , 41F
http://0rz.tw/g2ALP 應該是由左到右
11/25 13:13, 41F

11/25 13:13, , 42F
還是要推一下221大的結論, 分開寫就好了急什麼....XD
11/25 13:13, 42F

11/25 13:15, , 43F
上面沒寫由左到右
11/25 13:15, 43F

11/25 13:16, , 44F
function argument 裡的 , 並非 comma operator
11/25 13:16, 44F

11/25 13:16, , 45F
不是 sequence point
11/25 13:16, 45F

11/25 13:19, , 46F
那這樣就是我搞錯了! 對不起...我以為它算是comma operator
11/25 13:19, 46F

11/25 13:20, , 47F
>>會先印出222? printf("111"); 加上分號後是完整的
11/25 13:20, 47F

11/25 13:20, , 48F
statement,換言之,printf("111");一定會執行完才往下
11/25 13:20, 48F

11/25 13:21, , 49F
是要說 buffer overflow?這我不熟,但通常是用來搞破壞
11/25 13:21, 49F
某種情況真的會先輸出222...不用特別搞破壞就會這樣Orz ※ 編輯: ikari512 來自: 218.168.189.9 (11/25 13:27)

11/25 13:29, , 50F
舉個實例或實際的code吧, 理論上程式寫好應該不會發生這
11/25 13:29, 50F

11/25 13:30, , 51F
種狀況才對@_@"
11/25 13:30, 51F

11/25 14:12, , 52F
某種情況是指你的 libc 被人換掉的情況嗎? XD
11/25 14:12, 52F

11/25 21:19, , 53F
沒人知道嗎?蠻好奇先輸出222的原理
11/25 21:19, 53F
查到了... 有時需要fflush(stdout); 才會正確 剛寫的筆記.. 寫的應該不是完全正確 參考看看orz http://tinyurl.com/ycmaw2d

11/25 21:37, , 54F
反正這樣用 gg 的下場就是 gg.....
11/25 21:37, 54F
yes -_- ※ 編輯: ikari512 來自: 218.168.189.9 (11/25 23:34)

11/25 23:43, , 55F
感謝提供資訊。
11/25 23:43, 55F

11/26 00:01, , 56F
老實說寫 C 寫了十年多... 沒聽過 printf 有這種事... XD
11/26 00:01, 56F

11/26 00:04, , 57F
Sorry請問你有實際例子嗎 無意冒犯 但是我理解不能
11/26 00:04, 57F

11/26 00:05, , 58F
queue就算沒flush也不應該倒置 所以希望看到例子 謝謝您
11/26 00:05, 58F

11/26 01:13, , 59F
可能是某些情況輸出緩衝區卡住, 導致後面的print直接被
11/26 01:13, 59F

11/26 01:14, , 60F
丟出output了?? 不過實在是不容易自己生個案例來....Orz
11/26 01:14, 60F
我想我舉的例子有可能錯了 剛試了連續printf兩行不同的東西十萬次,然後導到檔案 還沒發現有錯亂 我想問的應該是以下三篇文章提到的 http://tinyurl.com/yd2axek http://tinyurl.com/ydysex3 http://tinyurl.com/yd6tccj ※ 編輯: ikari512 來自: 218.168.189.9 (11/26 02:06)

11/26 03:28, , 61F
以下三篇, 1. 沒錯亂, 2.3. 應該都是 i/o buffer 不同一個
11/26 03:28, 61F

11/26 03:28, , 62F
的問題
11/26 03:28, 62F

11/26 09:18, , 63F
我也是想的跟樓上一樣 QQ
11/26 09:18, 63F

11/26 09:55, , 64F
第三篇看到最後的解釋才大概懂是怎麼一回事....Orz
11/26 09:55, 64F

11/26 09:56, , 65F
話說, 一直不知道printf有"\n"就有ffflush(stdout)的效
11/26 09:56, 65F

11/26 09:56, , 66F
果說@_@" 所以cout<<"\n"的話也就不用特別<<endl嗎?_?
11/26 09:56, 66F

11/26 12:16, , 67F
cout \n只有印換行 endl才是換行+清緩衝
11/26 12:16, 67F

11/26 12:21, , 68F
我也是覺得, 印換行是印換行, 清緩衝是清緩衝, 所以會覺
11/26 12:21, 68F

11/26 12:21, , 69F
得有一篇說printf+"\n"有清緩衝的效果覺得怪怪的@_@"
11/26 12:21, 69F

11/27 14:39, , 70F
me too, 不過有個可能性會繞過去,那即是破壞了堆疊
11/27 14:39, 70F

11/27 23:41, , 71F
在寫網路程式的時候,為了操作fd,可能會加入write()直接
11/27 23:41, 71F

11/27 23:41, , 72F
印出來,的確有可能先前的printf()結果較慢出來
11/27 23:41, 72F
文章代碼(AID): #1B37CFW9 (C_and_CPP)
文章代碼(AID): #1B37CFW9 (C_and_CPP)