如何更快地判斷算術運算有沒有溢位?

2021-09-29 09:08:33 字數 3209 閱讀 8739

在編寫**的過程中,算術溢位是一件讓人十分頭疼的事。因此在**中檢測是否溢位是一件很有必要的事,那麼該如何檢測算術運算中的溢位呢?

以c語言中的算術乘法為例,可以使用以下的**檢測是否有溢位:

//判斷a與b的乘積是否溢位,是返回-1,否返回0

int overflow(int a,int b)

在函式中,首先計算a與b的乘積temp,然後再計算temp除以b。如果得到的結果是a的話,那麼就沒有溢位,否則運算過程中發生了溢位。誠然,該函式可以有效地檢測算術乘法是否溢位,但是對於cpu來說,除法的開銷相對於加法、移位等操作來說是非常大的,因此我們應該嘗試避免。

在這裡,我們嘗試使用組合語言來判斷算術運算中的溢位。

首先,讓我們來了解一些背景知識。

組合語言中set指令根據條件碼的組合,將乙個位元組設定為0或1。 指令

同義指令

效果設定條件

sete d

setz

d ← zf

equal / zero

setne d

setnz

d ← ~zf

not equal / not zero

sets d

d ← sf

negative

setns d

d ← ~sf

nonnegative

setg d

setnle

d ← ~(sf ^ of) & ~zf

greater (signed >)

setge d

setnl

d ← ~(sf ^ of)

greater or equal (signed >=)

setl d

setnge

d ← sf ^ of

less (signed <)

setle d

setng

d ← (sf ^ of) | zf

less or equal (signed <=)

seta d

setnbe

d ← ~cf & ~zf

above (unsigned >)

setae d

setnb

d ← ~cf

above or equal (unsigned >=)

setb d

setnae

d ← cf

below (unsigned <)

setbe d

setna

d ← cf | zf

below or equal (unsigned <=)

在這裡,我們的目標是讀取到of這個標誌位。但是在上表中,並不能單獨地把of標誌位存到暫存器中。仔細觀察後可以發現,上表中可以設定sf^of(setl)和sf(sets)這兩個標誌位,而(sf^of)^sf=of!因此,我們只需要將使用setl和sets指令設定兩個暫存器的值,然後再將這兩個暫存器中的值異或就可以得到of標誌位的值。

話不多說,讓我們開始吧!

首先編寫signedoverflow.c檔案:

int signedoverflow(int a,int b)

使用gcc -og -s signedoverflow.c命令產生的彙編檔案如下:

.file	"signedoverflow.c"

.text

.globl signedoverflow

.def signedoverflow; .scl 2; .type 32; .endef

.seh_proc signedoverflow

signedoverflow:

.seh_endprologue

movl %ecx, %eax

imull %edx, %eax

ret.seh_endproc

.ident "gcc: (x86_64-posix-seh-rev0, built by mingw-w64 project) 7.3.0"

然後我們在此基礎上實現檢測溢位的函式:

.file	"signedoverflow.c"

.text

.globl signedoverflow

.def signedoverflow; .scl 2; .type 32; .endef

.seh_proc signedoverflow

signedoverflow:

.seh_endprologue

movl %ecx, %eax

imull %edx, %eax ;計算%edx與%ecx的乘積

sets %r10b ;設定%r10b暫存器的值為sf

setl %r11b ;設定%r11b暫存器的值為sf^of

xorb %r10b, %r11b ;異或%r10b與%r11b,得到of,結果存在%r11b中

movl $0, %eax ;將返回值置為0

movl $-1, %r10d ;將%r10d的值置為-1

testb %r11b, %r11b ;測試%r11b(of)

cmovne %r10d, %eax ;如果%r11b不為0,將返回值置為-1

ret ;函式返回

.seh_endproc

.ident "gcc: (x86_64-posix-seh-rev0, built by mingw-w64 project) 7.3.0"

編寫完成後,使用gcc -og -c signedoverflow.s生成signedoverflow.o目標檔案。

再編寫測試函式main.c:

#include //判斷a與b的乘積是否溢位,是返回-1,否返回0

int signedoverflow(int a,int b);

int main()

使用gcc -og main.c signedoverflow.o得到可執行檔案a.exe。執行a.exe得到結果:

-1

0

大功告成!

在雲中更快地開發和部署

通過 ibm 進行企業雲應用程式開發和交付,使您的工作更為簡單。我們細心處理 細節,使您可以集中精力進行創新。使用我們經過驗證的應用程式模式,更快地構建應用程式。或者,使用我們的開發人員套件 英文 建立您自己的模式。使用以上任何一種方法,您都可以快速部署到公共雲或私有雲。我們還對 devops 進行...

讀書技巧 如何最快地汲取營養

網上看到時寒冰寫的這篇關於讀書技巧的文章。其觀點實用易懂,推薦伯友閱讀。以下是作者的觀點 一 高效率的讀書方式 讀書是獲取知識 活躍思維 提高自我的捷徑。我從小讀書深受表哥的影響,以古今文學名著為主。那個時候差不多能夠讀到的書,也基本上都是文學類的 文學是那個時候的主流,作家最吃香,連人找物件都強調...

算術左移後溢位判斷

取一位元組為例,能表示的數字從 128 127 先看正數,比如 9,就是 0000 1001,最高位 符號位 和資料最高位都是 0.左移得到 0001 0010 也就是 18 再看負數 9,就是 0000 1001 也就是 1111 0110 1 即 1111 0111,最高位 符號位 和資料最高位...