如何识别装配while (1)和do ... while装配之间的区别?
谢谢
如何识别装配while (1)和do ... while装配之间的区别?
谢谢
这个答案假定您要比较while (1)与do { } while(1)为简单起见,而是应与其他的条件下工作:
以这两个小 C 程序为例:
只是while:
#include <stdio.h>
int main(){
while(1)
printf("This is a loop\n");
return 0;
}
和do while:
#include <stdio.h>
int main(){
do
printf("This is a loop\n");
while(1);
}
使用 gcc/clang 生成特定于平台的程序集(我在 Intel Mac 上)gcc -S loop.c,我们可以看到调用的差异:
只是while:
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 11
.globl _main
.align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $0, -4(%rbp)
LBB0_1: ## =>This Inner Loop Header: Depth=1
leaq L_.str(%rip), %rdi
movb $0, %al
callq _printf
movl %eax, -8(%rbp) ## 4-byte Spill
jmp LBB0_1
.cfi_endproc
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "This is a loop\n"
.subsections_via_symbols
do while:
.section __TEXT,__text,regular,pure_instructions
.macosx_version_min 10, 11
.globl _main
.align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp0:
.cfi_def_cfa_offset 16
Ltmp1:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp2:
.cfi_def_cfa_register %rbp
subq $16, %rsp
movl $0, -4(%rbp)
LBB0_1: ## =>This Inner Loop Header: Depth=1
leaq L_.str(%rip), %rdi
movb $0, %al
callq _printf
movl %eax, -8(%rbp) ## 4-byte Spill
## BB#2: ## in Loop: Header=BB0_1 Depth=1
movb $1, %al
testb $1, %al
jne LBB0_1
jmp LBB0_3
LBB0_3:
movl -4(%rbp), %eax
addq $16, %rsp
popq %rbp
retq
.cfi_endproc
.section __TEXT,__cstring,cstring_literals
L_.str: ## @.str
.asciz "This is a loop\n"
.subsections_via_symbols
请注意LBB0_3从do while代码生成的额外子例程。我们得到了额外的 Jump Not Equal 指令,因为我们需要在执行while完do块中的语句后检查表达式的条件是否已经满足。
这是关于堆栈溢出的有用资源:while(true) / while(1) vs. for(;;)
正如 Igor Skochinsky 在评论中提到的,使用优化 ( -O3)编译每个程序将为您提供完全相同的程序集。虽然这个练习是在没有优化的小程序上完成的,但实际上,两个循环完成相同的事情并且(取决于编译器)可能会生成相同的程序集。实际上,很难(如果不是不可能的话)区分使用while(1)和的循环do { } while(1),因为它们都做同样的事情。