Maybe it is best to consider a small example:
Code:
int main(void)
{
volatile int x;
x = 3;
x += 4;
printf("The answer is %d\n", x);
return EXIT_SUCCESS;
}
Try to compile this program (with optimizations turned on) and then look at disassembly output. For gcc you can do this with `objdump -D' on the executable produced.
Code:
406a2c: 55 push %ebp
406a2d: 89 e5 mov %esp,%ebp
406a2f: 83 e4 f0 and $0xfffffff0,%esp
406a32: 83 ec 20 sub $0x20,%esp
406a35: e8 46 af ff ff call 401980 <___main>
406a3a: c7 44 24 1c 03 00 00 movl $0x3,0x1c(%esp)
406a41: 00
406a42: 8b 44 24 1c mov 0x1c(%esp),%eax
406a46: 83 c0 04 add $0x4,%eax
406a49: 89 44 24 1c mov %eax,0x1c(%esp)
406a4d: 8b 44 24 1c mov 0x1c(%esp),%eax
406a51: 89 44 24 04 mov %eax,0x4(%esp)
406a55: c7 04 24 64 80 40 00 movl $0x408064,(%esp)
406a5c: e8 4f a9 ff ff call 4013b0 <_printf.constprop.0>
My assembler is a bit rusty, but it should be clear that distinct operations are being performed on each of the operands 4 and 3, and an `add' operation is being executed in the CPU.
Now if you take out volatile and recompile, you get the following simplified output
Code:
406a35: e8 46 af ff ff call 401980 <___main>
406a3a: c7 44 24 04 07 00 00 movl $0x7,0x4(%esp)
406a41: 00
406a42: c7 04 24 64 80 40 00 movl $0x408064,(%esp)
406a49: e8 62 a9 ff ff call 4013b0 <_printf.constprop.0>
Now, the compiler can make the trivial optimization and simply load the final result into a register. No mathematical operation is needed.
In reality you wouldn't use volatile in this way, but it is just to demonstrate.