1

I am writing an embedded C code. Which if condition would be faster/optimized:

if (a == false)
{
    Some code
}

OR

if (a != true)
{
    Some code
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
user3220717
  • 57
  • 1
  • 3
  • 4
    If you are sure that it matters (e.g. because it's the hotspot of the whole program), examine the optimized assembly outputs from the compiler. It's very likely that they are identical. – kotatsuyaki Oct 23 '22 at 04:33
  • The question is senseless without a specific architecture in mind. Please edit it so that it can be answered. (Though people will still attempt to answer questions that can be answered, but that's how it is...) – Lundin Oct 25 '22 at 06:36
  • 1
    Stylistically neither is good practice. Testing a Boolean for equality to a Boolean literal is unnecessary and in C where true and false are defined rather then built-in it is potentially unsafe. `if( !a )` is better (not faster). The performance is irrelevant; it is unlikely to make any difference, and may even generate identical code. But really if you are second guessing the compiler at this level, you are not going to be very productive. You should generally consider performance at the algorithm and data structure design level, not at the code generation level; that is the compiler's job. – Clifford Oct 25 '22 at 09:38

3 Answers3

3

If a is of type bool, you won't be able to spot a difference — probably even if you look at the assembly language code. Certainly, it is unlikely to be a measurable difference, especially if Some code is more than a single instruction (or thereabouts). But only measurement or scrutiny of the assembly language can show you the difference.

If a is of type int (or any other non-bool type), the conditions have different meanings and at most one of them is correct. The first is equivalent to a == 0; the second is equivalent to a != 1. Unless a is restricted to the range 0 and 1, the results are different when a is 2, for example.

The idiomatic test would be if (!a) and that works the same for bool and non-bool types. You probably won't be able to spot any difference here, either.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
3

Reading this question, the first thing that came to my mind is "That's ridiculous, the compiler knows better and will optimize it anyway, right?"

Well, turns out I was wrong, here is how MSVC /O2 compiles it:

With if (a == false):

84 C9    | test    cl, cl

With if (a != true):

80 F9 01 | cmp     cl, 1

Well, that's weird. Mike Nakis explained the difference between cmp and test in this answer. And Peter Cordes commented below:

There can be a perf difference on Intel Core2 or Nehalem, where TEST can macro-fuse with more flavours of JCC than CMP. e.g. Core2 and Nehalem can macro-fuse test eax,eax / js, but not cmp eax,0 / js. Nehalem can macro-fuse cmp eax,0 / jl, though. (Core2 can't, but Core2 can only macro-fuse at all in 32-bit mode).

I believe this is true, test can be faster on some CPUs, but I don't believe its effect is measurable in practical scenarios.

Weirdly enough, for GCC, both -O2 and -O3 prefer cmp over test and will produce the same output for both cases.

Related: Test whether a register is zero with CMP reg, 0 vs OR reg, reg

thedemons
  • 1,139
  • 2
  • 9
  • 25
  • 1
    Note that the question is tagged with `embedded`, so it's likely that the author is not targeting the X86 ISA. These differences in the generated code may still hold, but only the author is able to find it out. – kotatsuyaki Oct 23 '22 at 04:55
  • 1
    Yes, I agree in practical scenario it might not be possible to measure the difference. But it's good to understand the difference and write the code correct/optimized in the first place... thanks for the answer.. – user3220717 Oct 23 '22 at 05:02
  • This is what you'd expect from a naive `bool` implementation that simply did the equivalent of `typedef uint8_t bool;`. In that case the tests expand to `if (a == 0)` and `if (a != 1)` which are different for a general `uint8_t`, and the compiler generates the correct code for each. gcc optimizes on the assumption that a `bool` will never contain any value except 0 and 1. MSVC may not be performing such an optimization, either because they never bothered to implement it, or to avoid breaking code that does weird hacks like storing other values in a `bool` variable. – Nate Eldredge Oct 23 '22 at 05:37
  • 1
    For gcc, the relevant difference is that `cmp cl, 1` sets the carry flag when `cl == 0`, whereas `test cl, cl` sets the zero flag. Using the carry flag allows the compiler to do the `sbb` hack to get a 32-bit result. For the zero flag, it could use `setz al`, but that only writes the low 8 bits, so they'd need another instruction to do `xor eax, eax` first. – Nate Eldredge Oct 23 '22 at 05:43
1

Same thing. Or just do if (!a) { /* code */ }

jgpixel
  • 103
  • 2
  • 6