>为什么printf(“hello world”)最终使用汇编代码中的更多cpu指令(不考虑使用的标准库)而不是cout<< “你好,世界”?
对于C,我们有:
对于C,我们有:
movl $.LC0,%esi movl $_ZSt4cout,%edi call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
对于C:
movl $.LC0,%eax movq %rax,%rdi movl $0,%eax call printf
我正在使用gcc 4.5.2版
解决方法
对于Linux x86_64上的64位gcc -O3(4.5.0),它读取:cout<< “你好,世界”
movl $11,%edx ; String length in EDX movl $.LC0,%esi ; String pointer in ESI movl $_ZSt4cout,%edi ; load virtual table entry of "cout" for "ostream" call _ZSt16__ostream_insertIcSt11char_traits...basic_ostreamIT_T0_ES6_PKS3_l
并且,对于printf(“Hello World”)
movl $.LC0,%edi ; String pointer to EDI xorl %eax,%eax ; clear EAX (maybe flag for printf=>no stack arguments) call printf
这意味着,你的序列完全取决于任何具体的
编译器实现,其版本和可能的编译器选项.
您的编辑状态,您使用gcc 4.5.2(这是相当新的).
似乎4.5.2引入了额外的64位寄存器
这个顺序无论出于什么原因它将64位RAX保存到RDI
在把它归零之前 – 这绝对没有意义(至少对我而言).
更有趣的是:3个参数调用序列(g -O1 -S source.cpp):
void c_proc() { printf("%s %s %s","Hello","World","!") ; } void cpp_proc() { std::cout << "Hello " << "World " << "!"; }
导致(c_proc):
movl $.LC0,%ecx movl $.LC1,%edx movl $.LC2,%esi movl $.LC3,%edi movl $0,%eax call printf
.LCx是字符串,不涉及堆栈指针!
对于cpp_proc:
movl $6,%edx movl $.LC4,%edi call _ZSt16__ostream_insertIcSt11char_traits...basic_ostreamIT_T0_ES6_PKS3_l movl $6,%edx movl $.LC5,%edi call _ZSt16__ostream_insertIcSt11char_traits...basic_ostreamIT_T0_ES6_PKS3_l movl $1,%edx movl $.LC0,%edi call _ZSt16__ostream_insertIcSt11char_traits...basic_ostreamIT_T0_ES6_PKS3_l
你现在看到这是什么.
问候
RBO