c語言的算術運算溢位問題

2021-10-04 14:50:14 字數 3194 閱讀 9584

1、 關於溢位的結論:可能出現的情況是結果的資料型別定義的小了,導致結果不正確。

關於計算溢位,看書上說的c語言中有符號數計算溢位的話會不知道發生什麼(溢位結果未定義),看編譯器怎麼處理。我在keil上試了下,溢位會把溢位部分砍掉,比如定義的是short型的,結果保留2個位元組。

short aa=-32767;

short bb=32;

short cc;

cc= aa- bb;

cc=7fe1;

如果擴充套件到jint,結果是ffff7fe1.

檢查是否溢位加 if(aa < 0 && aa -(-32768) >=bb)

參考:這篇文章中說的整數轉型溢位感覺比較常見還容易忽略,謹記。主要是負數的時候。

示例二:整形轉型時的溢位 1

2 34 5

6 78 9

10 11

12 13

intcopy_something(char*buf,intlen)

returnmemcpy(mybuf, buf, len);

}

上面這個例子中,還是[1]處的if語句,看上去沒有會問題,但是len是個signed int,而memcpy則需乙個size_t的len,也就是乙個unsigned 型別。於是,len會被提公升為unsigned,此時,如果我們給len傳乙個負數,會通過了if的檢查,但在memcpy裡會被提公升為乙個正數,於是我們的mybuf就是overflow了。這個會導致mybuf緩衝區後面的資料被重寫。

uint8_t合併成uint16_t時   在keil上試的不加uint16_t也可以。

uint16_t lebuftouint16(uint8_t *_pbuf)

再試:short  a = int16_max;

shor b = 32;

int cc = a + b;

結果正確。再試:

int a = int32_max;

int b = 32;

uint32_t  c = a+ b;

c=0x8000001f

"我們來看一段**:

voidfoo(intm,intn)

上面這段**有兩個風險:1)有符號轉無符號2)整型溢位。這兩個情況在前面的那些示例中你都應該看到了。所以,你千萬不要把任何檢查的**寫在 s = m + n 這條語名後面,不然就太晚了。undefined行為就會出現了——用句純正的英文表達就是——「dragon is here」——你什麼也控制不住了。(注意:有些初學者也許會以為size_t是無符號的,而根據優先順序 m 和 n 會被提公升到unsigned int。其實不是這樣的,m 和 n 還是signed int,m + n 的結果也是signed int,然後再把這個結果轉成unsigned int 賦值給s)"

3、用「ul」避免keil c51大整數常量運算溢位錯誤

keil c51是與ansi c相容的編譯器,ansi c規範規定十進位制整數常量的預設資料型別是int、long int和unsigned long int的其中一種,對給定的常量是其中的哪一種要看這個常量的實際大小,如果常數在-32768~32767之間則按int型別處理,如果按int型別處理會溢位就考慮long int或更大的資料型別unsigned long int。總之,編譯器總是按盡可能的原則指定常量的型別。

但這一原則並不總能奏效,當兩個常量做運算時就可能導致溢位。如:

#define sysclk                        22118400    // sysclk in hz (22.1184 mhz external crystal oscillator)

#define slider_rest_time    100              // in ms,slider rest time

#define rest_delay               sysclk * slider_rest_time / (65536 * 1000)

unsigned char i;

i = rest_delay;

在keil c51中執行i為0xe1,即225,並不是期望的結果22118400 * 100 / (65536 * 1000) = 33.75,取整為33。原因分析如下:

巨集替換後為:i = 22118400 * 100 / (65536 * 1000);,編譯器首先為22118400定義型別,因為22118400不在int的表示範圍內,而在long int的範圍-2147483648~2147483647內,所以22118400按long int型別處理,在做乘積運算時100被自動按long int處理,22118400 * 100將按兩帶符號長整型常量進行運算,運算結果仍為帶符號長整型,結果寫成十六進製制是0x83d60000,其十進位制是-2083127296,顯然出現了溢位錯誤。keil編譯器並沒有給出任何錯誤或警告提示資訊(vc++6.0還給出警告warning c4307: '*' : integral constant overflow),繼續進行下乙個運算65536 * 1000,結果為帶符號長整型,十六進製制為0x3e80000,十進位制為65536000,最後按兩長整型除法計算-2083127296 / 65536000,結果為0xffffffe1,由於i為字元型別,取0xffffffe1的最低有效位元組為0xe1賦值給i,i的最終值為0xe1。

解決這種溢位錯誤的方法用c語言的乙個術語就是「提公升」(promotion),拿上例來說就是將22118400指定為無符號長整型,即:

#define sysclk                        22118400ul

注:雖然只要將22118400、100、65536和1000四個常數中的乙個指定為無符號長整型即可得到正確的結果,但考慮到可讀性及規範性,應選擇大整數指定其型別。

小結:按c51編譯器的預設型別整數常量運算可能出現溢位錯誤,對大整數應指定其資料型別以避免出現可能的運算錯誤。

**:幽幽靈貓

c語言之堆疊溢位問題

對於c來說,函式呼叫,系統要做三個工作 這裡多提一下,關於陣列作為形參呼叫函式時,為什麼需要連同陣列長度一起傳進來?這裡是因為,陣列作為引數傳遞的本質只是乙個指標,也就是乙個位址,編譯器並不關心這個位址後邊有多少有用資料,編譯器只看得到指標所指的資料。所以在被呼叫函式中,無法直接知道這個陣列的長度,...

C語言遇到的陣列溢位問題

今天寫了個判斷陣列中資料的最大值問題的 發現了乙個有趣的情況,陣列溢位值總是乙個 現附上今天寫的判斷陣列最大值的 define crt secure no warnings 1 include includeint main int max num 0 int i 0 for i 0 i sizeo...

C 聯合Halcon記憶體溢位問題

最近寫了乙個halcon聯合c 的程式,實際使用過程中發現執行乙個小時多一點點就會報錯,大概估計是記憶體方向的問題,去看了windows錯誤日誌,鎖定了是 system.outofmemoryexception 也就是記憶體溢位了,回過頭來去查 把halcon中的object物件使用後均釋放掉,同時...