4
unsigned int a=200;
//mov   dword ptr [a],0C8h  
a >>= 1;
//mov   eax,dword ptr [a]  
//shr   eax,1  
//mov   dword ptr [a],eax  
a /= 2;
//mov   eax,dword ptr [a]  
//shr   eax,1  
//mov   dword ptr [a],eax  
int b = -200;
//mov   dword ptr [b],0FFFFFF38h  
b /= 2;
//mov   eax,dword ptr [b]  
//cdq  
//sub   eax,edx  
//sar   eax,1  
//mov   dword ptr [b],eax  
b >>= 1;
//mov   eax,dword ptr [b]  
//sar   eax,1  
//mov   dword ptr [b],eax 

im using msvc, // is the assembly for that C statement.

Why is signed int /=2 is different from >>=1? What are cdq and sub doing? Are they necessary?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
sunkue
  • 278
  • 1
  • 9
  • 1
    C says they round differently for negative numbers (toward 0 vs. toward -Inf); the asm has to reflect that. – Peter Cordes Jun 07 '20 at 14:35
  • 2
    Because `-7 / 2 = -3` but with `>> 1` you will get `-4` – Alex Lop. Jun 07 '20 at 14:36
  • all of you, thanks a lot. i under stand why are they differ-. – sunkue Jun 07 '20 at 14:44
  • 1
    Arithmetic right shift vs logical right shift. some ISAs have a real or pseudo ASR instruction to handle this some dont and you have to synthesize it. – old_timer Jun 07 '20 at 15:05
  • 1
    https://stackoverflow.com/questions/7622/are-the-shift-operators-arithmetic-or-logical-in-c implementation-defined (I didnt check a current spec) as to whether the C compiler is arithmetic or logical so that same code on certain compilers and/or with certain command line options may produce the same results for divide and shift. implementation defined. – old_timer Jun 07 '20 at 15:17
  • The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 / 2 E2 . If E1 has a signed type and a negative value, the resulting value is implementation-defined. – old_timer Jun 07 '20 at 15:22
  • a draft from 2007. so dont assume that a signed right shift is arithmetic...use divide and let the compiler optimize it into an arithmetic shift. – old_timer Jun 07 '20 at 15:23

2 Answers2

7

Dividing a negative integer by 2 is not the same as shifting it to the right by 1. For example

-7 / 2 = -3

With shifts:

11111001b >> 1 = 11111100b which is -4

Thus the compiler has to take care of the case when the integer is negative

What are cdq and sub doing? Are they necessary?

cdq performs the following EDX:EAX ← sign-extend of EAX.

Thus if the value in EAX is negative, EDX will get 0xFFFFFFFF (which is -1), otherwise it will be 0 (due to the sign extension of EAX).

sub eax, edx ; will either result in 'eax - 0' (if EAX is positive) or
             ;                       'eax - (-1)' (if EAX is negative)

Which in case of the above example will normalize the -7 to -7 - (-1) = -6 and then -6 >> 1 = -3.

Alex Lop.
  • 6,810
  • 1
  • 26
  • 45
1

Arithmetic shift right is actually the divide by 2 but is rounded to the nearest smaller integer. so -7 >> 1 is -4

Mathematical divide (as required by C standard) by two is rounded to the nearest absolute integer instead (ie towards zero).

The code is compiling to another sets of instreuctions:

        mov     edx, DWORD PTR x
        mov     eax, edx
        shr     eax, 31
        add     eax, edx
        sar     eax
        mov     DWORD PTR x, eax

https://godbolt.org/z/No6u6V

0___________
  • 60,014
  • 4
  • 34
  • 74
  • Divide by 2 of an odd number is exactly half way between two integers. The question is which one it picks, out of the two equidistant choices. C99 requires it to pick truncation toward 0 (unlike arithmetic right shift, which is like division by 2 with rounding toward -Inf.) – Peter Cordes Jun 07 '20 at 15:02
  • @PeterCordes It is what I wrote. Now I made it clearer – 0___________ Jun 07 '20 at 15:05
  • 2
    I'm not familiar with "nearest absolute integer" meaning towards zero. Is that terminology standard? A google search for `nearest absolute integer` doesn't turn up anything that would indicate it means towards zero. So yes, good edit, it needed that clarification. – Peter Cordes Jun 07 '20 at 15:09
  • 1
    Note that "towards zero" is a C99 and later requirement and OP has "im using msvc" which is not C99 compliant. With C89, `/2` and `>>1` may be the same. – chux - Reinstate Monica Jun 07 '20 at 15:24