1. 程式人生 > >C中的除法,商和余數的大小、符號如何確定

C中的除法,商和余數的大小、符號如何確定

spa 匯編碼 來看 div 最大整數 () 以及 有時 取余

對於C中的除法,商和余數的大小、符號是如何確定的呢?在C89中,只規定了如果兩個數為正整數,那麽余數的符號為正,並且商的值是接近真實值的最大整數。比如5 / 2,那麽商就是2,余數就是1。但是,C89裏面對於被除數和除數裏面,有負整數時,商的大小以及余數的符號沒有做出明確的規定,而只是說這依賴於具體實現。在Windows下(是Intel匯編指令),看如下如下例子:

int main() {
    int a = -5;
    int b = a / 3;
}

接下來看匯編碼:

; 1    : int main() {

    push    ebp
    mov    ebp, esp
    
sub esp, 8 ; 2 : int a = -5; mov DWORD PTR _a$[ebp], -5 ; fffffffbH ; 3 : int b = a / 3; mov eax, DWORD PTR _a$[ebp] cdq mov ecx, 3 idiv ecx ;idiv執行有符號的除法,並且余數的符號和被除數一樣 mov DWORD PTR _b$[ebp], eax ; 4 : }

匯編碼中,最重要的就是idiv指令,這個指令運行後的結果是余數的符號會保持和被除數一樣,同時,對於除法來說,余數的絕對值要小於除數的絕對值,這樣,我們就可以確定商、余數的大小以及符號。對於上面的例子-5 / 3來說,商就是-1,余數就是-2。

有時,由於除法可以轉換成加減法以及算數右移來執行,匯編碼不會用到idiv指令(這可以看成是一種優化),但是結果不會有影響,比如看下面的-5 / 2的匯編指令,就沒有用到idiv,但是結論和上面一樣,商是-2,余數是-1:

; 1    : int main() {

    push    ebp
    mov    ebp, esp
    sub    esp, 8

; 2    :     int a = -5;

    mov    DWORD PTR _a$[ebp], -5            ; fffffffbH

; 3    :     int b = a / 2;
mov eax, DWORD PTR _a$[ebp] cdq sub eax, edx sar eax, 1 ;算數右移操作 mov DWORD PTR _b$[ebp], eax ; 4 : ; 5 : }

上面的結論在Linux下(AT&T風格的匯編)同樣成立,雖然匯編碼和Intel匯編不一樣。

另外,C89中規定,對於%取余運算符,只適用於整型

C中的除法,商和余數的大小、符號如何確定