In C, is indexing an array faster than the ?:
operator?
For example, would (const int[]){8, 14}[N > 10]
be faster than N > 10? 14 : 8
?
In C, is indexing an array faster than the ?:
operator?
For example, would (const int[]){8, 14}[N > 10]
be faster than N > 10? 14 : 8
?
Stick with the ternary operator:
Mandatory quote (emphasis mine):
Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%
— Donald Knuth • https://wiki.c2.com/?PrematureOptimization
Now that's out of the way, let's compare what compilers actually produce.
#include <stdlib.h>
int ternary(int n) { return n > 10 ? 14 : 8; }
int array(int n) { return (const int[]){8, 14}[n > 10]; }
Compile with (g)cc 10.2.1 in Ubuntu and optimizations enabled:
$ cc -O3 -S -fno-stack-protector -fno-asynchronous-unwind-tables ternary.c
-S
stops after compilation and does not assemble. You will end up with a .s
file which contains the generated assembly code. (the -fno…
flags are to disable additional code generation which is not required for our example).
ternary.s
assembly code, lines unrelated to the methods removed:
ternary:
endbr64
cmpl $10, %edi
movl $8, %edx
movl $14, %eax
cmovle %edx, %eax
ret
array:
endbr64
movq .LC0(%rip), %rax
movq %rax, -8(%rsp)
xorl %eax, %eax
cmpl $10, %edi
setg %al
movl -8(%rsp,%rax,4), %eax
ret
.LC0:
.long 8
.long 14
If you compare them, you will notice a lot more instructions for the array version: 6 instructions vs. 4 instructions. There is no reason to write the more complicated code which every developer has to read twice; the shorter and straight-forward code compiles to more efficient machine code.
Use of the compound literal (and array in general) will be much less efficient as arrays are created (by current real-world compilers) despite the optimization level. Worse, they're created on the stack, not just indexing static constant data (which would still be slower, at least higher latency, than an ALU select operation like x86 cmov
or AArch64 csel
which most modern ISAs have).
I have tested it using all compilers I use (including Keil and IAR) and some I don't use (icc and clang).
int foo(int N)
{
return (const int[]){8, 14}[N > 10];
}
int bar(int N)
{
return N > 10? 14 : 8;
}
foo:
mov rax, QWORD PTR .LC0[rip] # load 8 bytes from .rodata
mov QWORD PTR [rsp-8], rax # store both elements to the stack
xor eax, eax # prepare a zeroed reg for setcc
cmp edi, 10
setg al # materialize N>10 as a 0/1 integer
mov eax, DWORD PTR [rsp-8+rax*4] # index the array with it
ret
bar:
cmp edi, 10
mov edx, 8 # set up registers with both constants
mov eax, 14
cmovle eax, edx # ALU select operation on FLAGS from CMP
ret
.LC0:
.long 8
.long 14