首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C 語言 32 位有符號整數加法溢出判斷與飽和運算實現

     編輯:程式設計綜合問答

溢出判斷邏輯

有符號 32 位整數範圍:`[-2^31, 2^31-1]` = `[-2147483648, 2147483647]`。

加法溢出條件:

  • 正溢出:`x > 0 && y > 0 && x + y < 0` (結果變負)。
  • 負溢出:`x < 0 && y < 0 && x + y > 0` (結果變正)。
  • 異號相加永不溢出。

飽和加法實現 (標準 C)


#include 
#include 

int32_t sat_add(int32_t x, int32_t y, int32_t* flag) {
    int64_t sum = (int64_t)x + y; // 擴展到 64 位判斷,避免 UB
    if (sum > INT32_MAX) {
        if (flag) *flag = INT32_MAX; // 正溢出
        return INT32_MAX;
    }
    if (sum < INT32_MIN) {
        if (flag) *flag = INT32_MIN; // 負溢出
        return INT32_MIN;
    }
    if (flag) *flag = 0; // 無溢出
    return (int32_t)sum;
}

無符號減法飽和


uint32_t sat_sub(uint32_t x, uint32_t y, int32_t* flag) {
    if (x < y) { // 無符號下溢
        if (flag) *flag = -1;
        return 0; // 飽和到 0
    }
    if (flag) *flag = 0;
    return x - y;
}

題目測試案例解析 (假設 int32_t)

輸入 x輸入 y數學和溢出類型輸出結果說明
-2147483648-128-2147483776負溢出-2147483648 (INT32_MIN)超出下界,飽和到最小值
-2147483648-2147483648-4294967296負溢出-2147483648同理,注意:若用補碼環繞會得到 0,但飽和語義要求飽和
2147483647-1282147483519無2147483519範圍內
214748364612147483647無2147483647恰好等於最大值

關鍵陷阱:有符號溢出是 UB (Undefined Behavior)

C 標準規定有符號整數溢出行為未定義,編譯器可假設不發生溢出並優化掉判斷代碼。因此不能寫 `if (x+y > INT_MAX)`,必須:

  1. 擴展至更寬類型判斷 (`int64_t`)。
  2. 或用編譯器內建:`__builtin_sadd_overflow(x, y, &res)` (GCC/Clang)。
  3. 或用無符號運算判斷:`(x ^ y) >= 0 && (x ^ (x+y)) < 0` (位運算技巧)。

位運算判斷溢出 (無需 64 位)


int32_t sat_add_fast(int32_t x, int32_t y, int32_t* flag) {
    int32_t sum = x + y;
    // 同號且結果號異於運算元 → 溢出
    bool overflow = ((x ^ y) >= 0) && ((x ^ sum) < 0);
    if (overflow) {
        if (flag) *flag = (x > 0) ? INT32_MAX : INT32_MIN;
        return (x > 0) ? INT32_MAX : INT32_MIN;
    }
    if (flag) *flag = 0;
    return sum;
}

總結

  • 溢出判斷核心:同號相加、結果異號。
  • 飽和語義:溢出時返回邊界值 (`INT_MAX`/`INT_MIN`/`0`),而非環繞。
  • 生產代碼優先用 `` 固定寬度類型與編譯器內建函數,兼容性與性能最佳。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved