printf:函數參數計算從右向左,從左向右?


造冰箱的大熊貓@cnblogs 2019/8/3

 

1、問題

某天寫了如下代碼:

unsigned char ReadByteFromFile ( FILE * fp )
{
  unsigned char ch;
  ...
  fread ( &ch, 1, 1, fp );
  ...
  return ch;
}
  
void main()
{
  ...
  printf ( "first byte = 0x%02x, second byte = 0x%02x\n", ReadByteFromFile ( fp ), ReadByteFromFile ( fp ) );
  ...
}

printf所在行的代碼本意是從文件中連續讀兩個字節並打印出來。假設被讀取文件的內容為“0x01 02 03 04 ... ...”,那么預期的運行結果是:

first byte = 0x01, second byte = 0x02

但實際運行結果(Ubuntu,gcc編譯)卻顛倒了個:

first byte = 0x02, second byte = 0x01

 

2、解答

嗯嗯,有意思。回想了很久以前上課內容並上網搜索一番,發現C標准里沒有規定編譯器在計算函數參數的次序(This form of argument-passing is known as call by value. The standard does not specify any order for the
evaluation of the arguments.)。也就是說,原想着printf()在運行時按照從左向右的順序計算參數值,在這里也就順序讀取了文件中的兩個字節。但實際上,編譯器輸出的結果卻是printf()函數按照從右向左的次序計算參數,這就導致了printf()中第一個ReadByteFromFile()函數(從左向右數)后讀取文件,而第二個ReadByteFromFile()卻先讀取文件,最終輸出結果與預想的次序顛倒。

或者用Stackoverflow上某個用戶提出的問題更好地說明這一問題:為什么下面代碼輸出結果是“4 5 5 4 5”。

main()
{
    int i = 5; printf ( "%d %d %d %d %d %d", i++, i--, ++i, --i, i); }

 因此,在使用函數中如果涉及對同一變量/對象的多次操作,一定要考慮到編譯器在處理函數參數計算時次序的不確定性。建議遇到這種情況時,還是現在函數外完成計算,再將計算結果傳遞給printf()。當然,如果能夠約定編譯器中參數計算次序(最好從左向右,與日常習慣相符),還是能省些事情,讓代碼看起來/寫起來簡潔一些。

 

2019.8.5補充:現在回想,好像當年上課的時候有過講授這方面的知識還有對應的考題,但真的太久遠了都忘記了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM