在编译成汇编语言的C语言中,puts和printf有什么区别?

11

这是我使用puts()的C程序:

#include <stdio.h>
int main(void){
puts("testing");
}

使用gcc -S -o sample.s sample.c将其编译为汇编代码,这是我得到的结果:

        .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(),这是我的结果:

    .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,然后将 %eax 移动到 (%esp),而 puts() 函数直接将 mov %.LC0 移动到 (%esp)。我不知道这是为什么。


6
可能是因为 printf 是一个变参函数,与有固定参数数量的函数调用方式不同。 - Barmar
1
有趣的是,在Mac上使用clang编译器,这两个程序都会编译成相同的汇编代码。 - Leandros
另外,为什么GCC在Linux上编译位置相关的代码? - Leandros
6
在编译时启用优化。如果没有启用优化,GCC会生成大量不必要的代码,从而影响代码性能。 - Ross Ridge
2
汇编输出在非最大优化级别下并不重要,你所看到的是编译器使代码变得更冗长,以便在调试器或人类阅读时更容易跟踪。 - M.M
显示剩余5条评论
1个回答

7
这两个函数在汇编级别的主要区别是,puts()函数只需要一个参数(一个指向要显示的字符串的指针),而printf()函数需要一个参数(指向格式字符串的指针),然后是任意数量的堆栈参数(printf()是可变参数函数)。
请注意,没有对参数数量进行任何检查,它仅取决于格式字符串中字符%出现的次数。例如,这种特殊性被用于格式字符串格式漏洞利用方法,以交互方式探索进程的堆栈内容。
因此,基本上,区别在于puts()只有一个参数,而printf()是可变参数函数。
如果您想更好地理解这种差异,请尝试编译:
#include <stdio.h>

int main(void) {
    printf("testing %d", 10);
}

1
值得一提的是,与fputs不同,'puts'隐含地附加了\n。请参阅编译器将printf优化为puts的两种情况和不优化的两种情况以及https://dev59.com/UZXfa4cB1Zd3GeqPhqCk。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接