在 C/C++ 面試中,關於 float 強制轉換為 int 與 int& 的行為差異是一道高頻考題。以下面這段代碼為例:
[cpp]
int test() {
float a = 1.0f;
cout << "value of (int)a is " << (int)a << endl;
cout << "value of &a is " << &a << endl;
cout << "value of (int &)a is " << (int &)a << endl;
cout << boolalpha << ((int)a == (int &)a) << endl;
return 0;
}
輸出結果往往令人驚訝:(int)a 輸出 1,而 (int&)a 卻輸出一個巨大的整數 1065353216。為什麼會這樣?這背後涉及 C++ 中 & 符號的雙重含義——「取地址」與「引用」——以及數據在內存中的真實佈局。
(int)a:構造新值(int)a 是一個值轉換操作。編譯器會讀取浮點數 a 的值(1.0),然後根據整數的表示規則,「構造」一個值為 1 的新整數。這是語義層面的轉換,生成的是一個全新的臨時變量。
(int&)a:別名綁定 / 內存重新解釋(int&)a 則完全不同。這裡的 & 表示引用。這行代碼告訴編譯器:「請把變量 a 佔用的那 4 個字節內存,當作一個 int 類型的左值來看待。」不發生任何數據複製或轉換,只是改變了編譯器對這塊內存的「解釋權」。
浮點數 1.0f 在內存中(遵循 IEEE 754 標準,小端序)的十六進制表示為 0x3F800000。當我們強行用 int& 去綁定這塊內存時,編譯器將這 4 個字節按有符號整數方式解讀:
0x3F800000 = 1065353216 (十進制)
這就是輸出巨大整數的由來。同理,0.0f 的內存全為 0,因此 (int)0.0f 與 (int&)0.0f 在這種特殊情況下恰好相等。
查看彙編代碼可以明確驗證:(int)a 對應 cvttss2si 等轉換指令,確實重新構造了值;而 (int&)a 只是傳遞地址給 cout<< 的重載版本,純粹是類型信息的傳遞,零開銷。
理解了基本概念後,我們通過一組綜合實驗來鞏固 *(指標)與 &(引用/取地址)的組合用法:
[cpp]
int test() {
int i = 10;
int *a = &i; // a 是指標,指向 i 的地址
cout << "value of a is " << a << endl; // 輸出 i 的地址
int &b = i; // b 是引用,i 的別名,共用同一地址
cout << "value of b is " << b << endl; // 輸出 10
cout << "value of &b is " << &b << endl; // 輸出 i 的地址
int *&c = a; // c 是「指標的引用」,別名綁定指標 a 本身
cout << "value of c is " << c << endl; // c 與 a 完全等價
// int & *d = b; // 錯誤:引用不是對象,無法定義「指向引用的指標」
return 0;
}
b 即操作 i。c 是 a 的別名,修改 c 會影響 a 的指向。指標與引用是 C/C++ 核心機制。指標提供間接訪問與動態內存管理能力;引用提供別名綁定,簡化語法並保證安全性。(int)a 與 (int&)a 的巨大差異,本質上揭示了「值語義」與「內存視圖重新解釋」的根本區別。掌握這一點,不僅能通過面試,更能在系統編程、序列化、網絡協議解析等場景中遊刃有餘。