但可透過以下 4 種標準模式實現「多值返回」語意,各有適用場景。
// C 風格
void swap(int *a, int *b) {
int t = *a; *a = *b; *b = t;
}
int x=1, y=2; swap(&x, &y); // x=2, y=1
// C++ 引用風格 (更安全、語法簡潔)
void swap(int &a, int &b) {
int t = a; a = b; b = t;
}
swap(x, y); // 無需取址
適用:修改現有變數、輸出 2-3 個相關值、C 代碼庫慣用。
缺點:呼叫端需預先宣告變數、函數簽名不直觀表達「輸出」。
// C 結構體
typedef struct { int quot; int rem; } DivResult;
DivResult divmod(int a, int b) {
return (DivResult){ a / b, a % b }; // C99 複合字面量
}
// 使用
DivResult r = divmod(10, 3); // r.quot=3, r.rem=1
// C++ 類/結構體 (可加建構函數、運算子)
struct DivResult { int quot, rem; };
DivResult divmod(int a, int b) { return {a/b, a%b}; }
auto [q, r] = divmod(10, 3); // C++17 結構化綁定
優點:語意自描述、型別安全、可攜帶錯誤碼、支援任意數量欄位、C++17 可直接解包。
缺點:大結構體返回可能涉及拷貝 (C++ 編譯器優化 RVO/NRVO 通常消除)。
// C: 返回動態分配結構體指標 (呼叫端負責 free)
DivResult *divmod_new(int a, int b) {
DivResult *r = malloc(sizeof(DivResult));
if (r) { r->quot = a/b; r->rem = a%b; }
return r;
}
// C++: 返回 unique_ptr (所有權轉移,自動釋放)
std::unique_ptr divmod_ptr(int a, int b) {
auto r = std::make_unique();
r->quot = a/b; r->rem = a%b;
return r;
}
適用:物件生命週期超出函數作用域、多態物件、可選返回 (回傳 NULL/nullptr 表示失敗)。
注意:C 版需明確文檔所有權歸屬;C++ 必用智慧指標。
// C: 呼叫端提供陣列緩衝區
void get_digits(int n, int digits[10], int *count) {
*count = 0;
while (n) { digits[(*count)++] = n % 10; n /= 10; }
}
int d[10], c; get_digits(12345, d, &c); // d={5,4,3,2,1}, c=5
// C++: 返回 vector (靈活大小、RAII)
std::vector get_digits(int n) {
std::vector d;
while (n) { d.push_back(n % 10); n /= 10; }
return d; // C++11 移動語義高效
}
適用:不定數量同類型值、序列處理。C 版需傳入最大容量與實際計數輸出參數。
// C: 返回錯誤碼,結果寫入輸出參數
typedef enum { OK, ERR_DIV_ZERO } ErrCode;
ErrCode safe_divmod(int a, int b, int *quot, int *rem) {
if (b == 0) return ERR_DIV_ZERO;
*quot = a / b; *rem = a % b;
return OK;
}
// C++: std::expected (C++23) 或 pair
#include
std::pair safe_divmod(int a, int b) {
if (b == 0) return {std::make_error_code(std::errc::invalid_argument), {}};
return {std::error_code{}, {a/b, a%b}};
}
將「成功/失敗」與「結果值」正交分離,避免「魔術返回值」(如 -1 表錯誤) 污染正常值域。
| 場景 | 推薦模式 | 理由 |
|---|---|---|
| 修改 1-3 個現有變數 | 輸出參數 (指標/引用) | 零分配、就地修改、C/C++ 通用 |
| 返回 2+ 相關欄位 (如商餘、座標、統計結果) | 返回結構體 | 語意清晰、型別安全、可擴展、C++17 可解包 |
| 物件生命週期長、多態、可選返回 | 返回智慧指標 (C++) / 結構體指標 (C) | 所有權語意明確、支援 nullptr 表失敗 |
| 不定長同類型序列 | 輸出陣列+計數 (C) / vector (C++) | 容量靈活、標準容器操作 |
| 需區分錯誤與正常值 | 返回錯誤碼+輸出參數 / expected/pair | 正交錯誤處理、避免魔術值 |
static int buf[2]; return buf; 非執行緒安全、覆蓋風險、僅限單執行緒簡易工具int* f() { static int a[3]; ... return a; } 同靜態變數問題DivResult& f() { DivResult r; return r; } 懸空引用,未定義行為「函數返回多個值」在 C/C++ 中本質是資料聚合問題。現代最佳實踐:
unique_ptr/shared_ptr)vector、C 緩衝區+長度)掌握這 4 種模式及其組合,即可優雅解決所有「多返回值」需求,寫出型別安全、語意清晰、可維護的代碼。