C/C++ 整數提升規則與編譯器選項交互作用,導致看似簡單的 -dt 運算在不同環境產生截然不同結果。本文深入剖析標準規定、編譯器實作差異與避坑指南。
char dt = '\1'; // 值為 1
long tdt = -dt; // 預期 -1,實際可能為 4294967295
標準規定:char、short 等「窄整數型別」參與運算前,必須提升為 int 或 unsigned int。
signed char → int(值保留)unsigned char → int(若 int 能表示所有值)或 unsigned intchar 有無號性由實作定義(ARM 通常 unsigned,x86 通常 signed)標準:The result of the unary - operator is the negative of its (promoted) operand.
unsigned 型別負號運算遵循模組 2N 規則(繞回)結果指派給 long tdt,發生**整數轉換**:
unsigned → signed 重新解讀位元模式)| 原始碼 | 預設 (GCC/x86) | -funsigned-char | -fsigned-char | XL C -qchars=signed |
|---|---|---|---|---|
char dt = 1; -dt | -1 (signed char → int) | 4294967295 (unsigned char → unsigned int → 模組轉換) | -1 | -1 |
signed char dt = 1; -dt | -1 | -1 | -1 | -1 |
unsigned char dt = 1; -dt | 4294967295 (提升為 unsigned int) | 4294967295 | 4294967295 | 4294967295 |
unsigned dt = 1; -dt | 4294967295 (unsigned int 直接運算) | 4294967295 | 4294967295 | 4294967295 |
-qupconv / -qlanglvl=extended
控制整數提升時是否保留 unsigned 屬性:
-qupconv:unsigned char → unsigned int(保留無號)-qnoupconv:unsigned char → int(傳統行為)-qlanglvl=extended 隱含 -qupconvchar 儲存數值,改用 int8_t/uint8_t (<cstdint>)。int val = dt; result = -val;。-fsigned-char 或 -funsigned-char,消除平台差異。-Wsign-conversion -Wsign-compare -Wconversion (GCC/Clang)。static_assert 驗證假設:
static_assert(std::is_signed_v<char>, "平台假設 char 為 signed");