Ich habe mit dem Compiler Explorer gespielt und bin auf ein interessantes Verhalten mit dem ternären Operator gestoßen, wenn ich so etwas verwendet habe:
std::string get_string(bool b)
{
return b ? "Hello" : "Stack-overflow";
}
Der vom Compiler generierte Code dafür (Clang Trunk, mit -O3) lautet wie folgt:
get_string[abi:cxx11](bool): # @get_string[abi:cxx11](bool)
push r15
push r14
push rbx
mov rbx, rdi
mov ecx, offset .L.str
mov eax, offset .L.str.1
test esi, esi
cmovne rax, rcx
add rdi, 16 #< Why is the compiler storing the length of the string
mov qword ptr [rbx], rdi
xor sil, 1
movzx ecx, sil
lea r15, [rcx + 8*rcx]
lea r14, [rcx + 8*rcx]
add r14, 5 #< I also think this is the length of "Hello" (but not sure)
mov rsi, rax
mov rdx, r14
call memcpy #< Why is there a call to memcpy
mov qword ptr [rbx + 8], r14
mov byte ptr [rbx + r15 + 21], 0
mov rax, rbx
pop rbx
pop r14
pop r15
ret
.L.str:
.asciz "Hello"
.L.str.1:
.asciz "Stack-Overflow"
Der vom Compiler generierte Code für das folgende Snippet ist jedoch erheblich kleiner und ohne Aufrufe memcpy
und es ist nicht wichtig, die Länge beider Zeichenfolgen gleichzeitig zu kennen. Es gibt 2 verschiedene Bezeichnungen, zu denen gesprungen wird
std::string better_string(bool b)
{
if (b)
{
return "Hello";
}
else
{
return "Stack-Overflow";
}
}
Der vom Compiler generierte Code für das obige Snippet (Clang Trunk mit -O3) lautet wie folgt:
better_string[abi:cxx11](bool): # @better_string[abi:cxx11](bool)
mov rax, rdi
lea rcx, [rdi + 16]
mov qword ptr [rdi], rcx
test sil, sil
je .LBB0_2
mov dword ptr [rcx], 1819043144
mov word ptr [rcx + 4], 111
mov ecx, 5
mov qword ptr [rax + 8], rcx
ret
.LBB0_2:
movabs rdx, 8606216600190023247
mov qword ptr [rcx + 6], rdx
movabs rdx, 8525082558887720019
mov qword ptr [rcx], rdx
mov byte ptr [rax + 30], 0
mov ecx, 14
mov qword ptr [rax + 8], rcx
ret
Das gleiche Ergebnis ist, wenn ich den ternären Operator verwende mit:
std::string get_string(bool b)
{
return b ? std::string("Hello") : std::string("Stack-Overflow");
}
Ich möchte wissen, warum der ternäre Operator im ersten Beispiel diesen Compilercode generiert. Ich glaube, dass der Schuldige in der const char[]
.
PS: GCC ruft strlen
im ersten Beispiel an, Clang jedoch nicht.
Link zum Compiler Explorer-Beispiel: https://godbolt.org/z/Exqs6G
Vielen Dank für Ihre Zeit!
Entschuldigung für die Codewand
const char*
während die Zeichenfolgen einzelnconst char[N]
s sind. Vermutlich könnte der Compiler letztere viel weiter optimieren