C 標準(C99 §6.9.1/12)規定:若函式宣告有返回型別(非 void),控制流到達函式末尾而未執行 return 表達式;,行為未定義。但若函式在某些路徑 return;(無表達式),另一些路徑 return 值;,語法上合法,編譯器通常只發出警告(-Wreturn-type),程式仍可編譯執行。
#include <stdio.h>
int f(int i) {
if (1)
return; // 無返回值
else
return 1; // 有返回值
}
int main(void) {
int i = -10;
printf("%d\n", f(i)); // 輸出 -10(實測 GCC x86-64)
return 0;
}
f 無參數實質使用,i 存於堆疊/暫存器。return; 相當於 ret 指令,不清理返回值暫存器(x86-64 的 RAX / ARM 的 R0)。printf 讀取 RAX,恰好殘留呼叫者 main 中的區域變數 i = -10(編譯器將 i 配置在 RAX 傳遞參數或暫存)。f:
push rbp
mov rbp, rsp
; if (1) 永真,直接跳轉
nop
pop rbp
ret ; 無 mov eax, ...,RAX 保持原值
main:
mov DWORD PTR [rbp-4], -10
mov eax, -10 ; 參數放入 EAX
call f
; f 返回後 RAX 仍為 -10
mov esi, eax
lea rdi, [format]
call printf
歷史包袱:早期 K&R C 無原型宣告,函式可隱式返回 int。ANSI C 為相容既有碼,未強制所有路徑必須有 return 表達式,僅規定「落出函式底部」為 UB。編譯器責任是診斷可達路徑缺失返回值,但非強制報錯。
| 工具 | 檢測能力 | 典型輸出 |
|---|---|---|
GCC/Clang -Wreturn-type | 路徑敏感分析 | warning: control reaches end of non-void function |
| Cppcheck | 跨函式路徑追蹤 | Function 'f' has no return statement on some paths |
| Coverity | 符號執行 | MISSING_RETURN 缺陷 |
MSVC /W4 | 資料流分析 | C4715: not all control paths return a value |