Tools like "compiler explorer" are great at answering questions like this. Fixing the bug in your code and comparing the following two snippets we see they produce identical assembly at -O1 and higher.
void trinary(int& val, int otherVal) {
val = (val != 0) ? otherVal : 0;
}
void nontrinary(int& val, int otherVal) {
if(val != 0) {
val = otherVal;
}
else {
val = 0;
}
}
trinary(int&, int):
mov eax, DWORD PTR [rdi]
test eax, eax
mov eax, 0
cmove esi, eax
mov DWORD PTR [rdi], esi
ret
nontrinary(int&, int):
mov eax, DWORD PTR [rdi]
test eax, eax
mov eax, 0
cmove esi, eax
mov DWORD PTR [rdi], esi
ret
What's interesting is that at -O0 they do not produce identical output. At -O0 the compiler uses eax
to explicitly store the result of the trinary operator, and then copies eax
into the correct register before returning. The non-trinary version does the assignment directly.
trinary(int&, int):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov DWORD PTR [rbp-12], esi
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax]
test eax, eax
je .L2
mov eax, DWORD PTR [rbp-12]
jmp .L3
.L2:
mov eax, 0
.L3:
mov rdx, QWORD PTR [rbp-8]
mov DWORD PTR [rdx], eax
nop
pop rbp
ret
nontrinary(int&, int):
push rbp
mov rbp, rsp
mov QWORD PTR [rbp-8], rdi
mov DWORD PTR [rbp-12], esi
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax]
test eax, eax
je .L5
mov rax, QWORD PTR [rbp-8]
mov edx, DWORD PTR [rbp-12]
mov DWORD PTR [rax], edx
jmp .L7
.L5:
mov rax, QWORD PTR [rbp-8]
mov DWORD PTR [rax], 0
.L7:
nop
pop rbp
ret
?:
conditional operator is not allowed to evaluate both of its arguments. – Capsularelse
after anif
statement, whether you write it or not... – Monogamy