Come esempio delle differenze, questo è assembly x86 creata usando gcc 4.4 con -O3
int arithmetic0 (int aValue)
{
return aValue/2;
}
00000000 <arithmetic0>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 8b 45 08 mov 0x8(%ebp),%eax
6: 5d pop %ebp
7: 89 c2 mov %eax,%edx
9: c1 ea 1f shr $0x1f,%edx
c: 8d 04 02 lea (%edx,%eax,1),%eax
f: d1 f8 sar %eax
11: c3 ret
int arithmetic1 (int aValue)
{
return aValue >> 1;
}
00000020 <arithmetic1>:
20: 55 push %ebp
21: 89 e5 mov %esp,%ebp
23: 8b 45 08 mov 0x8(%ebp),%eax
26: 5d pop %ebp
27: d1 f8 sar %eax
29: c3 ret
int arithmetic2 (int aValue)
{
return aValue * 2;
}
00000030 <arithmetic2>:
30: 55 push %ebp
31: 89 e5 mov %esp,%ebp
33: 8b 45 08 mov 0x8(%ebp),%eax
36: 5d pop %ebp
37: 01 c0 add %eax,%eax
39: c3 ret
int arithmetic3 (int aValue)
{
return aValue << 1;
}
00000040 <arithmetic3>:
40: 55 push %ebp
41: 89 e5 mov %esp,%ebp
43: 8b 45 08 mov 0x8(%ebp),%eax
46: 5d pop %ebp
47: 01 c0 add %eax,%eax
49: c3 ret
int arithmetic4 (int aValue)
{
return aValue/4;
}
00000050 <arithmetic4>:
50: 55 push %ebp
51: 89 e5 mov %esp,%ebp
53: 8b 55 08 mov 0x8(%ebp),%edx
56: 5d pop %ebp
57: 89 d0 mov %edx,%eax
59: c1 f8 1f sar $0x1f,%eax
5c: c1 e8 1e shr $0x1e,%eax
5f: 01 d0 add %edx,%eax
61: c1 f8 02 sar $0x2,%eax
64: c3 ret
int arithmetic5 (int aValue)
{
return aValue >> 2;
}
00000070 <arithmetic5>:
70: 55 push %ebp
71: 89 e5 mov %esp,%ebp
73: 8b 45 08 mov 0x8(%ebp),%eax
76: 5d pop %ebp
77: c1 f8 02 sar $0x2,%eax
7a: c3 ret
int arithmetic6 (int aValue)
{
return aValue * 8;
}
00000080 <arithmetic6>:
80: 55 push %ebp
81: 89 e5 mov %esp,%ebp
83: 8b 45 08 mov 0x8(%ebp),%eax
86: 5d pop %ebp
87: c1 e0 03 shl $0x3,%eax
8a: c3 ret
int arithmetic7 (int aValue)
{
return aValue << 4;
}
00000090 <arithmetic7>:
90: 55 push %ebp
91: 89 e5 mov %esp,%ebp
93: 8b 45 08 mov 0x8(%ebp),%eax
96: 5d pop %ebp
97: c1 e0 04 shl $0x4,%eax
9a: c3 ret
Le divisioni sono diversi - con la rappresentazione di un complemento a due, spostando un numero dispari negativo giusto si traduce in una valore diverso per dividerlo per due. Ma il compilatore ottimizza ancora la divisione in una sequenza di turni e aggiunte.
La differenza più ovvia è che questa coppia non fa la stessa cosa: cambiare per quattro equivale a moltiplicare per sedici, non otto! Probabilmente non otterresti un bug da questo se lascia che il compilatore sudizzi le piccole ottimizzazioni per te.
aNumber = aValue * 8;
aNumber = aValue << 4;
Domanda aggiuntiva: si comportano allo stesso modo in caso di overflow aritmetico? –
Non penso che il bithifting funzioni molto bene con i numeri negativi (o potrebbe non funzionare come previsto). I processori – Default
spesso (sempre?) Hanno uno spostamento aritmetico, ma non so se i compilatori C compilano in modo diverso se gli operandi sono firmati o meno. – ShinTakezou