作者wtchen (沒有存在感的人)
看板C_and_CPP
標題十三誡增修--07:不可以在數值運算、賦值或比較中隨意混用不同型別
時間Fri May 20 23:14:54 2016
誡7加了abs()可能<0的狀況。
========================================
07.
你不可以在數值運算、賦值或比較中隨意混用不同型別的數值,而不謹慎考
慮數值型別轉換可能帶來的「意外驚喜」(錯愕)。必須隨時注意數值運算
的結果,其範圍是否會超出變數的型別
錯誤例子:
unsigned int sum = 2000000000 + 2000000000; /* 超出 int 存放範圍 */
unsigned int sum = (unsigned int) (2000000000 + 2000000000);
double f = 10 / 3;
正確例子:
/* 全部都用 unsigned int, 注意數字後面的 u, 大寫 U 也成 */
unsigned int sum = 2000000000u + 2000000000u;
/* 或是用顯式的轉型 */
unsigned int sum = (unsigned int) 2000000000 + 2000000000;
double f = 10.0 / 3.0;
--------------------------------------------------
錯誤例子:
unsigned int a = 0;
int b[10];
for(int i = 9 ;
i >= a ; i--) { b[i] = 0; }
說明:由於 int 與 unsigned 共同運算的時候,會轉換 int 為 unsigned,
因此迴圈條件永遠滿足,與預期行為不符
--------------------------------------------------
錯誤例子: (感謝 sekya 網友提供)
unsigned char a = 0x80; /* no problem */
char b = 0x80; /* implementation-defined result */
if( b == 0x80 ) { /* 不一定恒真 */
printf( "b ok\n" );
}
說明:語言並未規定 char 天生為 unsigned 或 signed,因此將 0x80 放入
char 型態的變數,將會視各家編譯器不同作法而有不同結果
--------------------------------------------------
錯誤例子:
#include <math.h>
int a = -2147483648 ; // 2147483648 = 2 的 31 次方
while (abs(a)>0){ // abs(-2147483648)<0 有可能發生
++a;
}
說明:如果你去看C99/C11 Standard,你會發現long int (4 bytes)
變數的最大/最小值為(被define在limits.h)
INT_MIN -2147483647 // compiler實作時最小值不可大於 -(2147483648-1)
INT_MAX 2147483647 // compiler實作時最小值不可小於 (2147483648-1)
不過由於32bit能顯示的範圍就是2**32種,所以一般作業系統會把
INT_MIN多減去1,也就是int 的顯示範圍為-2147483648 ~ +2147483647。
當程式跑到abs(-2147483648)>0時,由於int不存在2147483648,
於是正確結果無法被有限的數位顯示(undefined behavior)。
(不只int,其他如long、long long等以此類推)
補充資料:
- C11 Standard 5.2.4.2.1, 7.22.6.1
-
https://www.fefe.de/intof.html
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 223.140.52.193
※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1463757297.A.596.html
※ 編輯: wtchen (223.140.52.193), 05/20/2016 23:20:46
推 EdisonX: 表達範圍是complier的事?我以為是補數系統的事… 05/21 09:39
→ Caesar08: 2**16改成2的16次方。C++沒有** 05/21 09:59
→ wtchen: 可是SHRT_MIN 應該是compiler (glibc?)定的吧? 05/21 10:01
→ wtchen: 2**16晚點改,moptt好難用@@ 05/21 10:02
推 siriusu: 竟然有這個case 05/22 10:55
根據推文修改好了。
※ 編輯: wtchen (223.137.128.153), 05/22/2016 22:31:36