As far as optimizations go, profiling is the best you can do. But let's have a look at the generated assembly nonetheless, as that can be useful too. I'll use the following dummy declarations:
namespace s {
void s_on();
void s_off();
};
struct Command {
int cmd;
int length;
};
int S_time;
The first version of your code compiled with Clang at -O3
produces:
foo(Command*): # @foo(Command*)
push rbx
mov rbx, rdi
mov eax, dword ptr [rbx]
cmp eax, 1
je .LBB0_3
test eax, eax
jne .LBB0_5
call s::s_off()
jmp .LBB0_4
.LBB0_3:
call s::s_on()
.LBB0_4:
mov eax, dword ptr [rbx + 4]
mov dword ptr [rip + S_time], eax
.LBB0_5:
pop rbx
ret
While the second version, with goto
, produces:
foo2(Command*): # @foo2(Command*)
push rbx
mov rbx, rdi
mov eax, dword ptr [rbx]
cmp eax, 4
je .LBB1_6
cmp eax, 1 # These two instructions
je .LBB1_4 # weren't here in the first version
test eax, eax
jne .LBB1_5
call s::s_off()
jmp .LBB1_5
.LBB1_4:
call s::s_on()
.LBB1_5:
mov eax, dword ptr [rbx + 4]
mov dword ptr [rip + S_time], eax
.LBB1_6:
pop rbx
ret
Not as clear as some other cases, but there is one difference: the first version only compares command[0].cmd
with 0
and 1
, but the second one compares it with 0
, 1
and 4
. Less code repetition does not necessarily mean more optimised code: you have actually hindered the optimiser and made it generate a useless special case for 4
.
goto
is not the low-level tool imbued with a magic low-level optimisation aura that its detractors describe. It's just a very basic flow control tool, which has few (but still some!) uses in C++ when the other tools don't cut it. It can, of course, be used for optimisation, but no better or more easily than any of the other ones.