#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`)。
int i = 0x12345678;
short s = i; // 截斷為 0x5678 (實現定義,通常取低位)
char c = i; // 截斷為 0x78
// 編譯器通常警告 (-Wconversion),但合法代碼
// 顯式轉型表達意圖:short s = (short)i;
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) (正數)
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 錯誤:括號改變優先級,先整除再轉
口訣:除法前**先轉型**,不要事後轉型。
char c = 200; // 若 char 有號 -> -56;無號 -> 200
// 位運算/比較易出錯
// 明確指定:
signed char sc = 200; // -56
unsigned char uc = 200; // 200
// 字串處理建議用 unsigned char / uint8_t
float f = 0.1f;
if (f == 0.1f) ... // 危險!0.1 無法精確表示為二進制浮點
// 正確:相對/絕對誤差比較
#define EPS 1e-6
if (fabs(a - b) < EPS) // 簡易版
// 嚴格版 (Bruce Dawson 算法): 相對誤差 + 絕對誤差 + ULP 比較
short a = -1; // 0xFFFF
unsigned int b = 1;
if (a > b) ... // true! a 提升為 int (-1) -> 再轉 unsigned int (UINT_MAX) -> 極大
// 規則:有號與無號運算 -> 皆轉無號
// 防禦:避免混合有號無號運算;必要時強轉統一類型