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

C 語言整數溢出檢測:從錯誤示範到正確姿勢的深度剖析

     編輯:關於C語言

問題背景

有符號整數溢出在 C/C++ 中屬於 未定義行為,編譯器可假設溢出不發生並進行激進優化,導致看似合理的檢測邏輯失效。本文以《程序猿之---C語言細節7》為基礎,系統梳理溢出檢測的演進邏輯。

錯誤示範:直接判斷和為負

int a = 123456789, b = 2147483000;
// 錯誤寫法
if (a + b < 0) printf("overflow\n");

失效原因:當目標架構的加法指令不設定符號標誌(如某些 DSP、或啟用 -fwrapv 以外的優化),編譯器可能直接優化掉判斷,或溢出時標誌位為「溢出」而非「負號」,導致條件不成立。

正確方法一:轉換為無符號數比較

#include 

if ((unsigned)a + (unsigned)b > INT_MAX) {
    printf("overflow\n");
}

原理:無符號整數運算在 C 標準中定義為模 2^N 環繞,無未定義行為。將兩個運算元強制轉為 unsigned 後相加,結果若超過 INT_MAX 必定發生環繞,此時無符號值會小於任一運算元,但直接與 INT_MAX 比較更直觀:(unsigned)a + (unsigned)b 的數學值等於真實和,若真實和 > INT_MAX,則無符號結果也 > INT_MAX(因為無符號最大值 UINT_MAX >= INT_MAX)。

正確方法二:避免加法,改用減法比較

if (a > INT_MAX - b) {
    printf("overflow\n");
}

優勢:完全在有符號範圍內運算,無需類型轉換,邏輯等價於 a + b > INT_MAX 但規避了溢出風險。同理,檢測下溢:a < INT_MIN - b。

擴展:通用安全加法函數

#include 
#include 

bool safe_add_int(int a, int b, int* result) {
    if ((b > 0 && a > INT_MAX - b) || (b < 0 && a < INT_MIN - b)) {
        return false; // 溢出
    }
    *result = a + b;
    return true;
}

編譯器輔助:內建函數與 Sanitizer

  • GCC/Clang 內建:__builtin_add_overflow(a, b, &result) 返回是否溢出,生成高效指令(如 x86 的 jo 跳轉)。
  • UndefinedBehaviorSanitizer (UBSan):編譯加 -fsanitize=undefined,運行時自動捕獲有符號溢出、移位超寬等 UB。

總結

整數溢出檢測的核心原則是 「先判斷,後運算」。推薦優先使用編譯器內建函數,次選減法比較法,嚴禁依賴未定義行為的事後檢查。養成使用 int32_t/uint32_t 等固定寬度類型的習慣,配合靜態分析工具,從源頭消除隱患。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved