遞歸函數漏寫 return 卻偶爾能得到正確結果,加入無關函數調用後卻輸出錯誤值。這背後是函數返回值在寄存器(如 EAX)傳遞的機制作祟。
// 例1:漏寫 return 卻正確
int Add_Recursion(int a, int b) {
int carry = 0, sum = 0;
if (b == 0) return a;
else {
sum = a ^ b;
carry = (a & b) << 1;
Add_Recursion(sum, carry); // 缺少 return!
}
}
// 例2:加入無關調用後出錯
int ChangeStack() { return 3; }
int Add_Recursion2(int a, int b) {
int carry = 0, sum = 0;
if (b == 0) return a;
else {
sum = a ^ b;
carry = (a & b) << 1;
Add_Recursion2(sum, carry);
ChangeStack(); // 污染 EAX
}
}
EAX 傳遞。return a; 編譯為 mov eax, a。return 時,函數結束不修改 EAX,調用者讀取的仍是 EAX 當前值。return a 設置 EAX,返回時上層未修改 EAX,故值傳遞正確(巧合)。ChangeStack() 執行 mov eax, 3,覆蓋了正確值,導致主函數讀到 3。int Add_Recursion3(int a, int b) {
int carry = 0, sum = 0;
if (b == 0) return a;
else {
sum = a ^ b;
carry = (a & b) << 1;
Add_Recursion3(sum, carry);
__asm__("movl $3, %eax"); // 強制修改 EAX
}
}
// 主函數將打印 3,證明返回值確實取自 EAX。
MSVC: warning C4715: not all control paths return a value
GCC: warning: control reaches end of non-void function
C++ 標準規定:到達非 void 函數末尾未返回值屬於未定義行為(UB)。
return 表達式;。return。-Wall -Werror),將警告視為錯誤。「漏寫 return 偶爾能工作」是未定義行為的典型表現,依賴特定調用約定與優化結果,極不可靠。理解返回值傳遞機制(寄存器/棧),養成嚴格返回習慣,是寫出健壯 C 代碼的基石。