首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言類型轉換與運算陷阱:溢位、截斷、整數除法、浮點精度完全避坑指南

     編輯:關於C語言

陷阱 1:整數運算溢位 (Undefined Behavior for Signed)


#include 
short s1 = SHRT_MAX; // 32767
short s2 = SHRT_MAX;
short r1 = s1 + s2; // 有號溢位 -> UB (結果不可預期,可能 -2)
int  r2 = s1 + s2;  // 提升為 int 運算 -> 正確 65534

// 無號整數溢位:定義行為 (模 2^N 環繞)
unsigned short u1 = USHRT_MAX; // 65535
unsigned short u2 = 1;
unsigned short u3 = u1 + u2; // 保證為 0 (模 65536)

規則:有號溢位是 **UB**,編譯器可假設不發生並優化掉檢查。無號溢位定義為模運算。**防禦**:寬類型運算、檢查邊界 (`if (a > MAX - b)`)、使用編譯器檢查 (`-ftrapv`, `-fsanitize=undefined`)。

陷阱 2:隱式截斷 (大類型賦值給小類型)


int i = 0x12345678;
short s = i;      // 截斷為 0x5678 (實現定義,通常取低位)
char c = i;       // 截斷為 0x78
// 編譯器通常警告 (-Wconversion),但合法代碼
// 顯式轉型表達意圖:short s = (short)i;

陷阱 3:浮點數賦值給整數 (截斷向零)


double pi = 3.14159;
int i = pi;       // 3 (直接捨棄小數部,**非四捨五入**)
int j = 3.9;      // 3
int k = -3.9;     // -3 (C99 規定向零截斷)
// 四捨五入需用: (int)round(x) / (int)floor(x+0.5) (正數)

陷阱 4:整數除法只得整數 (截斷商)


int a = 3, b = 2;
float f = a / b;       // 1.0 !!! 整數除法先算出 1,再轉 float
float f2 = a / (float)b; // 1.5 正確:至少一操作數為浮點
float f3 = (float)a / b; // 1.5 正確
float f4 = (float)(a / b); // 1.0 錯誤:括號改變優先級,先整除再轉

口訣:除法前**先轉型**,不要事後轉型。

陷阱 5:`char` 有號性不確定


char c = 200; // 若 char 有號 -> -56;無號 -> 200
// 位運算/比較易出錯
// 明確指定:
signed char sc = 200;   // -56
unsigned char uc = 200; // 200
// 字串處理建議用 unsigned char / uint8_t

陷阱 6:浮點數比較與精度


float f = 0.1f;
if (f == 0.1f) ... // 危險!0.1 無法精確表示為二進制浮點
// 正確:相對/絕對誤差比較
#define EPS 1e-6
if (fabs(a - b) < EPS) // 簡易版
// 嚴格版 (Bruce Dawson 算法): 相對誤差 + 絕對誤差 + ULP 比較

陷阱 7:整數提升與 usual arithmetic conversions


short a = -1; // 0xFFFF
unsigned int b = 1;
if (a > b) ... // true! a 提升為 int (-1) -> 再轉 unsigned int (UINT_MAX) -> 極大
// 規則:有號與無號運算 -> 皆轉無號
// 防禦:避免混合有號無號運算;必要時強轉統一類型

最佳實踐清單

  1. **開啟警告**:`-Wall -Wextra -Wconversion -Wsign-conversion -Wfloat-conversion`。
  2. **定寬類型**:`` `int32_t`, `uint16_t` 替代 `int`/`short`,明確寬度與有號性。
  3. **避免隱式轉型**:關鍵計算顯式 `static_cast` / C 風格轉型。
  4. **整數除法**:分母轉浮點或用定點數/分數結構體。
  5. **邊界檢查**:加法前 `if (a > MAX - b)`,乘法前 `if (a != 0 && b > MAX / a)`。
  6. **浮點比較**:封裝 `float_eq(a, b, eps)` 函數。
  7. **靜態分析/運行時檢測**:`-fsanitize=undefined,integer` 捕獲溢位、除零、移位溢位。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved