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 memcpyund 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 strlenim 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