The compiler will make the decision for you, if you use any meaningful optimization. Write whatever is cleanest and makes sense. To me that would be the first one, since it is less code and doesn't introduce more code paths. For fun, I did some tests in Clang 3.4 -O3:
bool happened = false;
extern volatile int dontOptMe1, dontOptMe2, dontOptMe3;
while (dontOptMe1) {
if (dontOptMe2) {
happened = true;
}
}
dontOptMe3 = happened;
vs
bool happened = false;
extern volatile int dontOptMe1, dontOptMe2, dontOptMe3;
while (dontOptMe1) {
if (dontOptMe2) {
if(!happened) happened = true;
}
}
dontOptMe3 = happened;
Resulted in the following in pseudo ASM:
MOV happened, 0
BRA LOOP_END
LOOP_START:
SELECTEQ dontOptMe2, 0, happened, happened, 1
LOOP_END:
BCZC dontOptMe1, LOOP_START
EXIT:
STORE dontOptMe3, happened
vs
MOV happened, 0
BCZS dontOptMe1, EXIT
LOOP:
SELECTNE dontOptMe2, 0, R2, 1, 0
SELECTEQ happened, 0, R3, 1, 0
AND R3, R2, R3
SELECTNE R3, 0, happened, 1, 0
BCZC dontOptMe1, LOOP
EXIT:
STORE dontOptMe3, happened
The first is much more desirable. This is also a good example of how restrictive volatile types are. I was surprised the compiler couldn't transform the second into the first.
Note: SELECTXX means, if Arg1 minus Arg2 sets condition code XX, set Arg3 to Arg4, otherwise set Arg3 to Arg5. So: SELECTNE dontOptMe2, 0, R2, 1, 0
is the equivalent of: R2 = (dontOptMe2 == 0) ? 1 : 0;
in C