Pergunta

Eu adivinhei, mas ainda fiquei surpreso ao ver que a saída desses dois programas, escritos em C e C++, quando compilados, eram muito diferentes.Isso me faz pensar que o conceito de objetos ainda existe mesmo no nível mais baixo.Isso adiciona sobrecarga?Em caso afirmativo, atualmente é uma otimização impossível converter código orientado a objetos em estilo processual ou apenas muito difícil de fazer?

olámundo.c

#include <stdio.h>

int main(void) {
    printf("Hello World!\n");
    return 0;
}

olámundo.cpp

#include <iostream>

int main() {
  std::cout << "Hello World!" << std::endl;
  return 0;
}

Compilado assim:

gcc helloworld.cpp -o hwcpp.S -S -O2
gcc helloworld.c -o hwc.S -S -O2

Produzido este código:

Montagem C

    .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

Montagem C++

    .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
Foi útil?

Solução

Compiladores diferentes produzem códigos diferentes.Uma versão anterior do gcc versus a versão atual do gcc provavelmente produz um código diferente.

Mais importante, iostream lida com muitas coisas stdio não, então obviamente haverá alguma sobrecarga substancial.Entendo que, em teoria, eles poderiam ser compilados em código idêntico, mas o que eles estão fazendo não é tecnicamente idêntico.

Outras dicas

Seu problema aqui não é sobre objetos ou otimização:é isso printf e cout são feras fundamentalmente muito diferentes.Para uma comparação mais justa, substitua seu cout instrução no código C++ com printf.A otimização é um ponto discutível quando você está enviando para stdout, pois o gargalo certamente será o buffer do terminal.

Você não está chamando as mesmas funções no exemplo C++ que no exemplo C.Substitua os tubos std::cout pelo antigo printf, assim como o código C, e você verá uma correlação muito maior entre a saída dos dois compiladores.

Você precisa perceber que há muitas "outras" coisas acontecendo em C++.Construtores globais, por exemplo.Além disso, as bibliotecas são diferentes.

o objeto stream C++ é muito mais complicado que C io, e se você olhar através do assembler poderá ver todo o código para pthreads na versão C++.

Não é necessariamente mais lento, mas certamente é diferente.

Eu adivinhei, mas ainda fiquei surpreso ao ver que a saída desses dois programas, escritos em C e C++, quando compilados, eram muito diferentes.

Estou surpreso que você tenha ficado surpreso - são programas totalmente diferentes.

Isso me faz pensar que o conceito de objetos ainda existe mesmo no nível mais baixo.

Absolutamente...objetos são a forma como a memória é organizada e usada durante a execução do programa (sujeita a otimizações).

Isso adiciona sobrecarga?

Não necessariamente ou normalmente - os mesmos dados teriam que estar em algum lugar de qualquer maneira se o trabalho estivesse sendo coordenado da mesma maneira lógica.

Em caso afirmativo, atualmente é uma otimização impossível converter código orientado a objetos em estilo processual ou apenas muito difícil de fazer?

O problema não tem nada a ver com OO versus código processual, ou com um sendo mais eficiente que o outro.O principal problema que você observa aqui é que os ostreams do C++ exigem um pouco mais de configuração e desmontagem e têm mais E/S coordenada pelo código embutido, enquanto printf() tem mais fora de linha na biblioteca pré-compilada para que você não consigo ver isso na sua pequena listagem de código.Não está claro o que é "melhor" e, a menos que você tenha um problema de desempenho relacionado ao perfil dos programas, você deve esquecê-lo e fazer alguma programação útil.

EDITAR em resposta ao comentário:

Chamada justa - foi redigida um pouco duramente - desculpe.Na verdade, é uma distinção difícil de fazer..."somente o compilador [sabe] de objetos" é verdade em certo sentido - eles não são "coisas" discretas e encapsuladas para o compilador da maneira que podem ser para o programador.E poderíamos escrever um objeto que pudesse ser usado exatamente como você usou cout isso desapareceria durante a compilação e produziria código equivalente à versão printf().Mas, cout e iostreams envolve alguma configuração porque é thread-safe e mais embutido e lida com diferentes localidades, e é um objeto real com requisitos de armazenamento porque carrega informações mais independentes sobre o estado do erro, se você deseja lançar exceções, condições de fim de arquivo (printf () afeta "errno", que é então derrotado pela próxima chamada de biblioteca/sistema operacional)....

O que você pode achar mais esclarecedor é comparar quanto código extra é gerado quando você imprime mais uma string, já que a quantidade de código é basicamente uma sobrecarga constante + alguma quantidade por uso e, em último caso, ostreamO código baseado em - pode ser tão ou mais eficiente que printf(), dependendo dos tipos e formatação solicitados.Também é importante notar que...

std::cout << "Hello world!\n";

...está correto e mais análogo à sua instrução printf()... std::endl solicita explicitamente uma operação de liberação desnecessária, já que um programa C++ compatível com o padrão irá liberar e fechar seus buffers conforme o fluxo sai do escopo de qualquer maneira (isto é, há uma postagem interessante hoje onde parece que o compilador Microsoft VisualC++ de alguém não está fazendo isso por eles!- vale a pena ficar de olho, mas é difícil de acreditar).

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top