Ja.
Sie können überprüfen, was ein Compiler tut, indem Sie seinen Assemblycode betrachten. Ich habe ein kleines C-Programm erstellt, um sicherzustellen, dass es etwas Variabilität hat, so dass der Optimierer nicht einfach alles konstant faltet.
#include <stdio.h>
void func1(const char input) {
printf("func1: %c\n", input);
}
void func2(const char input) {
printf("func2: %c\n", input);
}
void func3(const char input) {
printf("func3: %c\n", input);
}
int main() {
char input = (char)getchar();
if(input == 'Y') {
func1(input);
}
func2(input);
if(input == 'Y') {
func3(input);
}
}
Sie können die Baugruppe mit -S
generieren.
gcc -S test.c -o test.asm
Beachten Sie, dass dies ohne Optimierungen ist. Sie können den Vergleich finden, ohne viel Assembly lesen zu müssen, suchen Sie nach 89, die die ASCII-Dezimal-Darstellung von Y
ist.
LCFI10:
subq $16, %rsp
call _getchar
movb %al, -1(%rbp)
cmpb $89, -1(%rbp)
jne L5
movsbl -1(%rbp), %eax
movl %eax, %edi
call _func1
L5:
movsbl -1(%rbp), %eax
movl %eax, %edi
call _func2
cmpb $89, -1(%rbp)
jne L6
movsbl -1(%rbp), %eax
movl %eax, %edi
call _func3
L6:
movl $0, %eax
leave
Das ist eine ziemlich rote Übersetzung der beiden if-Blöcke. Sie können zwei cmpb $89, -1(%rbp)
Aufrufe sehen, die anzeigen, dass der Vergleich zweimal durchgeführt wird.
Jetzt mit Optimierungen: gcc -S -O3 test.c -o test.asm
LCFI0:
call _getchar
cmpb $89, %al
je L10
leaq lC1(%rip), %rdi
movsbl %al, %esi
xorl %eax, %eax
call _printf
L7:
xorl %eax, %eax
addq $8, %rsp
LCFI1:
ret
L10:
LCFI2:
leaq lC0(%rip), %rdi
movl $89, %esi
xorl %eax, %eax
call _printf
movl $89, %esi
xorl %eax, %eax
leaq lC1(%rip), %rdi
call _printf
movl $89, %esi
xorl %eax, %eax
leaq lC2(%rip), %rdi
call _printf
jmp L7
Jetzt ist es nur ein cmpb $89, %al
, aber es gibt auch mehr movl $89, %esi
. IC0, IC1 und IC2 sind die Strings "func1: %c\n"
, "func2: %c\n"
und "func3: %c\n"
, die den drei Funktionen entsprechen.
Zum Vergleich, hier ist was Clang tut.
Ltmp12:
.cfi_offset %rbx, -24
callq _getchar
movsbl %al, %ebx
movzbl %bl, %eax
cmpl $89, %eax
jne LBB3_2
## BB#1:
leaq L_.str(%rip), %rdi
xorl %eax, %eax
movl %ebx, %esi
callq _printf
leaq L_.str.1(%rip), %rdi
xorl %eax, %eax
movl %ebx, %esi
callq _printf
leaq L_.str.2(%rip), %rdi
jmp LBB3_3
LBB3_2:
leaq L_.str.1(%rip), %rdi
Wie bei gcc gibt es jetzt nur einen Vergleich. Und in ähnlicher Weise sind L_.str, L_.str.1 und L.str.2 die Zeichenfolgen in func1, func2 bzw. func3.
Beide haben im Wesentlichen den Code geändert, um dies zu sein.
if(input == 'Y') {
printf("func1: %c\n", input);
printf("func2: %c\n", input);
printf("func3: %c\n", input);
}
else {
printf("func2: %c\n", input);
}
Mit "invariant" meinen Sie "konstant"? –
Hängt davon ab. Ändert 'func2()' 'cond'? Kann 'gcc' * beweisen * dass es nicht ist? – EOF
Überprüfen Sie, indem Sie auf den Baugruppenausgang schauen. (Ich bin 100% sicher, dass es das optimiert.) Ich nehme an, mit "invariant" meinen Sie "konstanter Ausdruck". – Downvoter