这是我使用
puts()
的 C 程序:
#include <stdio.h>
int main(void){
puts("testing");
}
使用
gcc -S -o sample.s sample.c
将其编译成Assembly后,这就是我得到的:
.file "sample.c"
.section .rodata
.LC0:
.string "testing"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call puts
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.5 20110214 (Red Hat 4.4.5-6)"
.section .note.GNU-stack,"",@progbits
我也做了同样的事情,这次我使用
printf()
而不是 put,这就是我得到的:
.file "sample.c"
.section .rodata
.LC0:
.string "testing"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, %eax //this is the difference
movl %eax, (%esp)
call printf
leave
ret
.size main, .-main
.ident "GCC: (GNU) 4.4.5 20110214 (Red Hat 4.4.5-6)"
.section .note.GNU-stack,"",@progbits
这是我不明白的地方,
printf()
函数mov $.LC0
到%eax
,然后mov %eax
到(%esp)
,而puts()
函数mov %.LC0
直接到(%esp)
。
我不知道这是为什么。
在汇编级别,这两个函数之间的最大区别在于
puts()
函数仅采用一个参数(指向要显示的字符串的指针),而 printf()
函数将采用一个参数(指向要显示的字符串的指针)。格式字符串),然后是堆栈中任意数量的参数(printf()
是一个可变参数函数)。
请注意,绝对不会检查参数的数量,它仅取决于在格式字符串中遇到字符
%
的次数。例如,这种特殊性用于格式字符串格式错误利用方法,以交互方式探索进程堆栈的内容。
所以,基本上,区别在于
puts()
只有一个参数,而 printf()
是一个可变参数函数。
如果你想更好地理解这个区别,请尝试编译:
#include <stdio.h>
int main(void) {
printf("testing %d", 10);
}