为什么C和C++;即使在编译后也不一样? 我猜到了,但仍然惊讶地发现,这两个程序的输出,在C和C++编写时,是非常不同的。 这使我认为,对象的概念甚至在最低层次上仍然存在。 这会增加开销吗?如果是这样的话,将面向对象的代码转换成过程式是目前不可能的优化,还是很难做到 helloworld.c
生成此代码: C组件 C++汇编为什么C和C++;即使在编译后也不一样? 我猜到了,但仍然惊讶地发现,这两个程序的输出,在C和C++编写时,是非常不同的。 这使我认为,对象的概念甚至在最低层次上仍然存在。 这会增加开销吗?如果是这样的话,将面向对象的代码转换成过程式是目前不可能的优化,还是很难做到 helloworld.c,c++,c,compiler-theory,C++,C,Compiler Theory,生成此代码: C组件 C++汇编 不同的编译器产生不同的代码。早期版本的gcc与当前版本的gcc可能产生不同的代码 更重要的是,iostream处理了很多stdio没有处理的事情,因此显然会有一些巨大的开销。我知道,从理论上讲,它们可以被编译成缩进代码,但它们在技术上并不完全相同。你这里的问题不是关于对象或优化:而是printf和cout从根本上说是完全不同的。为了更公平的比较,C++代码中的 cOUT/COD>语句替换为 PROTFF < /代码>。当你输出到STDUT时,优化是一个很重要的问
不同的编译器产生不同的代码。早期版本的gcc与当前版本的gcc可能产生不同的代码
更重要的是,
iostream
处理了很多stdio没有处理的事情,因此显然会有一些巨大的开销。我知道,从理论上讲,它们可以被编译成缩进代码,但它们在技术上并不完全相同。你这里的问题不是关于对象或优化:而是printf
和cout
从根本上说是完全不同的。为了更公平的比较,C++代码中的<代码> cOUT/COD>语句替换为<代码> PROTFF < /代码>。当你输出到STDUT时,优化是一个很重要的问题,因为瓶颈肯定是终端的缓冲区。 你必须认识到C++中有很多其他的事情。 例如,全局构造函数。图书馆也不同
< C++流对象比C IO复杂得多,如果你查看汇编程序,你可以看到C++版本中所有线程的代码。不一定是慢的,但肯定不同。
< p> C++中没有调用与C示例相同的函数。用普通的printf替换std::cout管道,就像C代码一样,您应该会看到两个编译器的输出之间有更大的相关性 我猜到了,但仍然惊讶地发现,这两个程序的输出,在C和C++中编译时,有很大的不同。 我很惊讶你会感到惊讶-它们是完全不同的程序 这使我认为,对象的概念甚至在最低层次上仍然存在 绝对。。。对象是程序执行过程中内存的布局和使用方式(需进行优化) 这会增加开销吗 不一定或通常-如果以相同的逻辑方式协调工作,那么相同的数据无论如何都必须在某个地方 如果是这样的话,将面向对象的代码转换成过程式是目前不可能的优化,还是很难做到 这个问题与OO与过程代码无关,或者一个比另一个更有效。您在这里观察到的主要问题是,C++的OStream需要更多的设置和拆卸,并且有更多的I/O由内联代码协调,而printf()在预编译库中有更多的外联代码,因此您无法在小代码列表中看到它。现在还不清楚哪一个“更好”,除非你有一个性能问题,分析显示是相关的,否则你应该忘记它,做一些有用的编程 根据评论进行编辑: 公平的要求-措辞有点苛刻-抱歉。这是一个很难区分的事实。。。“只有编译器[知道]对象”在某种意义上是正确的——它们不是像程序员那样被封装在编译器中的、半神圣的离散“东西”。而且,我们可以编写一个对象,它可以像您使用的cout
一样使用,在编译过程中消失,并生成与printf()版本等效的代码。但是,cout
和iostreams涉及一些设置,因为它是线程安全的、更内联的,并且处理不同的区域设置,而且它是一个具有存储要求的真实对象,因为它包含有关错误状态的更多独立信息,无论您是否希望引发异常,文件结束条件(printf()影响“errno”,然后被下一个库/操作系统调用击垮)
您可能会发现更具洞察力的是,比较打印一个或多个字符串时生成的额外代码量,因为代码量基本上是一些恒定的开销+一些每使用量,在后一方面,基于ostream
的代码可以与printf()一样或更高效,具体取决于请求的类型和格式。同样值得注意的是
std::cout << "Hello world!\n";
std::cout+1用于发现差异,但请注意stdout
并不意味着终端,cout
的开销在重定向到磁盘文件时通常会对吞吐量产生负面影响。@Tony:是的,但当重定向到/dev/null
时,要击败的函数不是printf
,但是一个能够识别/dev/null
并完全跳过格式设置的人。@Ben Voigt:问题不在于开销、效率或其他方面。原来的程序是两个不同的程序,它们做不同的事情,它们必须以不同的方式编译。如果将相同的程序输入两个编译器,代码会更相似。这是两个不同的程序,它们唯一的共同点是屏幕上的最终输出。当然,它们必须以不同的方式编译。你为什么感到惊讶?我并不自称是专家。软件行业是严酷的。。。我很惊讶,因为我认为UndertheHood cout只是获取一个字符串并将其输出到控制台,就像printf一样,但有一些不同,我认为不必创建实际的对象,我认为只有编译器知道对象。
#include <iostream>
int main() {
std::cout << "Hello World!" << std::endl;
return 0;
}
gcc helloworld.cpp -o hwcpp.S -S -O2
gcc helloworld.c -o hwc.S -S -O2
.file "helloworld.c"
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello World!\n"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, 4(%esp)
movl $1, (%esp)
call __printf_chk
xorl %eax, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
.file "helloworld.cpp"
.text
.p2align 4,,15
.type _GLOBAL__I_main, @function
_GLOBAL__I_main:
.LFB1007:
.cfi_startproc
.cfi_personality 0x0,__gxx_personality_v0
pushl %ebp
.cfi_def_cfa_offset 8
movl %esp, %ebp
.cfi_offset 5, -8
.cfi_def_cfa_register 5
subl $24, %esp
movl $_ZStL8__ioinit, (%esp)
call _ZNSt8ios_base4InitC1Ev
movl $__dso_handle, 8(%esp)
movl $_ZStL8__ioinit, 4(%esp)
movl $_ZNSt8ios_base4InitD1Ev, (%esp)
call __cxa_atexit
leave
ret
.cfi_endproc
.LFE1007:
.size _GLOBAL__I_main, .-_GLOBAL__I_main
.section .ctors,"aw",@progbits
.align 4
.long _GLOBAL__I_main
.section .rodata.str1.1,"aMS",@progbits,1
.LC0:
.string "Hello World!"
.text
.p2align 4,,15
.globl main
.type main, @function
main:
.LFB997:
.cfi_startproc
.cfi_personality 0x0,__gxx_personality_v0
pushl %ebp
.cfi_def_cfa_offset 8
movl %esp, %ebp
.cfi_offset 5, -8
.cfi_def_cfa_register 5
andl $-16, %esp
pushl %ebx
subl $28, %esp
movl $12, 8(%esp)
movl $.LC0, 4(%esp)
movl $_ZSt4cout, (%esp)
.cfi_escape 0x10,0x3,0x7,0x55,0x9,0xf0,0x1a,0x9,0xfc,0x22
call _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_i
movl _ZSt4cout, %eax
movl -12(%eax), %eax
movl _ZSt4cout+124(%eax), %ebx
testl %ebx, %ebx
je .L9
cmpb $0, 28(%ebx)
je .L5
movzbl 39(%ebx), %eax
.L6:
movsbl %al,%eax
movl %eax, 4(%esp)
movl $_ZSt4cout, (%esp)
call _ZNSo3putEc
movl %eax, (%esp)
call _ZNSo5flushEv
addl $28, %esp
xorl %eax, %eax
popl %ebx
movl %ebp, %esp
popl %ebp
ret
.p2align 4,,7
.p2align 3
.L5:
movl %ebx, (%esp)
call _ZNKSt5ctypeIcE13_M_widen_initEv
movl (%ebx), %eax
movl $10, 4(%esp)
movl %ebx, (%esp)
call *24(%eax)
jmp .L6
.L9:
call _ZSt16__throw_bad_castv
.cfi_endproc
.LFE997:
.size main, .-main
.local _ZStL8__ioinit
.comm _ZStL8__ioinit,1,1
.weakref _ZL20__gthrw_pthread_oncePiPFvvE,pthread_once
.weakref _ZL27__gthrw_pthread_getspecificj,pthread_getspecific
.weakref _ZL27__gthrw_pthread_setspecificjPKv,pthread_setspecific
.weakref _ZL22__gthrw_pthread_createPmPK14pthread_attr_tPFPvS3_ES3_,pthread_create
.weakref _ZL20__gthrw_pthread_joinmPPv,pthread_join
.weakref _ZL21__gthrw_pthread_equalmm,pthread_equal
.weakref _ZL20__gthrw_pthread_selfv,pthread_self
.weakref _ZL22__gthrw_pthread_detachm,pthread_detach
.weakref _ZL22__gthrw_pthread_cancelm,pthread_cancel
.weakref _ZL19__gthrw_sched_yieldv,sched_yield
.weakref _ZL26__gthrw_pthread_mutex_lockP15pthread_mutex_t,pthread_mutex_lock
.weakref _ZL29__gthrw_pthread_mutex_trylockP15pthread_mutex_t,pthread_mutex_trylock
.weakref _ZL31__gthrw_pthread_mutex_timedlockP15pthread_mutex_tPK8timespec,pthread_mutex_timedlock
.weakref _ZL28__gthrw_pthread_mutex_unlockP15pthread_mutex_t,pthread_mutex_unlock
.weakref _ZL26__gthrw_pthread_mutex_initP15pthread_mutex_tPK19pthread_mutexattr_t,pthread_mutex_init
.weakref _ZL29__gthrw_pthread_mutex_destroyP15pthread_mutex_t,pthread_mutex_destroy
.weakref _ZL30__gthrw_pthread_cond_broadcastP14pthread_cond_t,pthread_cond_broadcast
.weakref _ZL27__gthrw_pthread_cond_signalP14pthread_cond_t,pthread_cond_signal
.weakref _ZL25__gthrw_pthread_cond_waitP14pthread_cond_tP15pthread_mutex_t,pthread_cond_wait
.weakref _ZL30__gthrw_pthread_cond_timedwaitP14pthread_cond_tP15pthread_mutex_tPK8timespec,pthread_cond_timedwait
.weakref _ZL28__gthrw_pthread_cond_destroyP14pthread_cond_t,pthread_cond_destroy
.weakref _ZL26__gthrw_pthread_key_createPjPFvPvE,pthread_key_create
.weakref _ZL26__gthrw_pthread_key_deletej,pthread_key_delete
.weakref _ZL30__gthrw_pthread_mutexattr_initP19pthread_mutexattr_t,pthread_mutexattr_init
.weakref _ZL33__gthrw_pthread_mutexattr_settypeP19pthread_mutexattr_ti,pthread_mutexattr_settype
.weakref _ZL33__gthrw_pthread_mutexattr_destroyP19pthread_mutexattr_t,pthread_mutexattr_destroy
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",@progbits
std::cout << "Hello world!\n";