Take the 2-minute tour ×

I have been looking at some simple C code and the different output from GCC using different optimization levels.

C code

#include <stdio.h>

int main() {
    int i = 0;

    while(i<10) {

    i = 0;

    while(i<10) {


When I compile the code using -Os or -O2 the first loop works a bit differently. It it decrements instead of incrementing, and it is in two different ways. I am wondering why it decrements instead of incrementing like in the code, and the the small difference between -Os and -O2.

-Os compiled

0x400486 <main+6>       mov     edi,0x40068c
0x40048b <main+11>      call    0x400450 <puts@plt>
0x400490 <main+16>      dec     ebx
0x400492 <main+18>      jne     0x400486 <main+6>

-O2 compiled

0x400490 <main+16>      mov    edi,0x40069c
0x400495 <main+21>      call   0x400450 <puts@plt>
0x40049a <main+26>      sub    ebx,0x1
0x40049d <main+29>      jne    0x400490 <main+16> 
share|improve this question

2 Answers 2

up vote 6 down vote accepted

By decrementing, compiler can make use of jne (jump if not equal/zero) which does the comparison (to zero) and jump in a single instruction. In case of incrementing, it would have to do a cmp/test (with 10) and then a conditional jump like jnz/jne. I believe it is a part of optimization.

-Os flag optimizes to bring down the code size. The code generated using -Os uses dec ebx instead of sub ebx, 0x1, since dec ebx is a 2-byte instruction while sub ebx, 0x1 is a 3-byte instruction (Note the address at which the next instruction begins). That explains the small difference.

share|improve this answer
This does explain the difference in one direction, but not the other; it seems that there must be an advantage of sub over dec otherwise O2 would not have chosen it. –  PlasmaHH Mar 11 '14 at 13:03
With a little research I think I found the reason why O2 uses sub instead of dec. Intel® 64 and IA-32 Architectures Optimization Reference Manual In table C-19 in appendix C add/sub has a lower latency. –  pyCtrl_ Mar 13 '14 at 12:37

Because I can't comment, I'll try to fix some inaccuracies in pnak4j's answer.

dec ebx is really a 1-byte instruction (I don't know why it appears to be 2-bytes). DEC sets the ZF flag accordingly to the result of (ebx-1) when: zero or not zero. Then, JNE does the jump if not zero (JNE/JNZ are the same). JMP is not a conditional jump, therefore it would not make much sense after CMP/TEST.

share|improve this answer
By jmp, I meant a conditional jump. An unconditional jump doesn't make much sense after a compare. It has been edited. Thanks. –  pank4j Mar 11 '14 at 7:20
dec ebx is 0xff 0xcb –  PlasmaHH Mar 11 '14 at 13:07

Your Answer


