首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C 語言函數參數求值順序與副作用:printf 參數求值陷阱

     編輯:程式設計疑難解答

現象代碼

int x = 1, y = 0;
printf("%d, x=%d, y=%d", x = y, x, y); // 輸出: 0, x=0, y=0

int swap(int *a, int *b) { int t=*a; *a=*b; *b=t; return 1; }
int main() {
    int x=1, y=0;
    printf("return of swap is %d\tx=%d,y=%d\n", swap(&x,&y), x, y); // 輸出: 1, x=1, y=0
    printf("\t\t\tx=%d,y=%d", x, y); // 輸出: x=0, y=1
}

核心解釋

C 標準未規定函數參數求值順序,編譯器通常**從右向左**壓棧 (cdecl 調用約定)。

逐步分析

  1. printf("...", swap(&x,&y), x, y):
    編譯器先計算右most參數 `y` (值 0) 壓棧 → `x` (值 1) 壓棧 → 執行 `swap(&x,&y)` (交換 x,y 為 0,1) 返回 1 壓棧。
    `printf` 從棧取值格式化:第一個佔位符 `%d` 取 1,第二個取壓棧時的 `x` (1),第三個取壓棧時的 `y` (0)。
    **關鍵**:壓棧時刻的 `x,y` 值被**複製**到棧幀,後續 `swap` 修改內存中的 `x,y` 不影響棧上副本。
  2. 第二個 `printf` 直接讀取當前內存 `x=0, y=1`,故顯示交換後值。

驗證:調整參數順序

printf("x=%d,y=%d\tswap return %d\n", x, y, swap(&x,&y)); // 先壓 swap 返回值,再壓 x,y (此時已交換) → 顯示交換後值

最佳實踐

  • 避免在函數參數中使用有副作用的表達式 (賦值、自增、函數調用修改全局狀態)。
  • 將副作用操作提取到單獨語句,再傳遞確定值。
  • 若需特定順序,用臨時變量明確順序:
int ret = swap(&x,&y);
printf("ret=%d, x=%d, y=%d", ret, x, y); // 順序明確,無歧義
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved