FAQ Lite
Compiladores

[ 33.1 ] Onde eu posso conseguir mais informações sobre o uso de MFC e Visual C++?
[ 33.2 ] Como eu exibo um texto na barra de status usando MFC?
[ 33.3 ] Como eu posso descompilar um executável de volta ao código fonte C++?
[ 33.4 ] Onde eu posso conseguir informações sobre compiladores C++ {Borland, IBM, Microsoft, Semantic, Sun, etc} ?
[ 33.5 ] Como os compiladores usam over-allocation para lembrar o número de elementos em uma matriz alocada dinamicamente?
[ 33.6 ] Como os compiladores usam matriz associativa para lembrar o número de elementos em uma matriz alocada dinamicamente?
[ 33.7 ] Se name mangling fosse padronizado, eu poderia ligar códigos compilados com diferentes compiladores de diferentes fornecedores?
[ 33.8 ] O compilador GNU C++ (g++) produz executáveis muito grandes para códigos fonte minúsculos. Porque?
[ 33.9 ] Há uma gramática yacc compatível com C++?
[ 33.10 ] O que é C++ 1.2? 2.0? 2.1? 3.0?

[ 33.1 ] Onde eu posso conseguir mais informações sobre o uso de MFC e Visual C++?

Em MFC/Visual C++ FAQ, mantida por Scot Wingo.
Topo
[ 33.2 ] Como eu exibo um texto na barra de status usando MFC?

Use a seguinte codificação:
    CString s = "Text";
    CStatusBar* p =
     (CStatusBar*)AfxGetApp()->m_pMainWnd->GetDescendantWindow(AFX_IDW_STATUS_BAR);
    p->SetPaneText(1, s); 
Isso funciona com MFC v.1.00. É de se esperar que funcione também com as versões posteriores.
Topo
[ 33.3 ] Como eu posso descompilar um executável de volta ao código fonte C++?

Você está brincando, não está?

Aqui estão umas poucas das muitas razões pelas quais isso não é nem remotamente factível:

  • Para começar: o que o faz pensar que o programa foi escrito em C++?
  • Mesmo que você esteja certo de que o programa, pelo menos em parte, foi escrito originalmente em C++, qual o compilador, entre os trocentos existentes, foi usado para produzi-lo?
  • Ainda que você saiba que compilador foi usado, que versão específica foi utilizada?
  • Ainda que você saiba o código de identificação do compilador pelo fabricante e o número da versão, quais as opções de compilação que foram usadas?
  • Ainda que você saiba o código de identificação do compilador pelo fabricante e o número da versão e as opções de compilação, quais as bibliotecas de terceiros que foram usadas e incorporadas ao programa, e quais as versões dessas bibliotecas?
  • Ainda que você saiba tudo isso, a maioria dos executáveis incorporam ao código suas próprias informações de debug, de tal forma que o programa descompilado seria ilegível.
  • Ainda que você saiba tudo sobre o compilador, fabricante, número de versão, opções de compilação, bibliotecas de terceiros e informações de debug, o custo de escrever um descompilador que funcionasse para um único compilador, e tivesse uma modesta taxa de sucesso, seria um esforço monumental. 

Mas a grande questão não é como descompilar o código de outros, mas porque você quer fazer isso? Se você está tentando engenharia reversa sobre o código de outros, é uma vergonha; procure um trabalho honesto. Se você está tentando recuperar um código fonte perdido, a melhor sugestão que tenho é fazer backups mais seguros da próxima vêz.

Topo
[ 33.4 ] Onde eu posso conseguir informações sobre compiladores C++ {Borland, IBM, Microsoft, Semantic, Sun, etc}?

Em ordem alfabética pelo nome do vendedor:

Qualquer sugestão para acréscimos a essa lista deve ser enviada para cline@parashift.com ou arnaut@vicosa.com.br

Topo
[ 33.5 ] Como os compiladores usam over-allocation para lembrar o número de elementos em uma matriz alocada dinamicamente?

Recorde-se de que quando você delete[] uma matriz, o sistema de execução sabe, como que por mágica, quantos destrutores executar. Essa FAQ descreve uma técnica usada por alguns compiladores C++ para conseguir isso. Uma outra ténica comum é usar uma matriz associativa.

Se o compilador usa a técnica over-allocation, o código para p = new Fred[n] se parecerá com o exemplo dado a seguir. Note que WORDSIZE é uma constante imaginária, dependente da máquina, que contém o valor de sizeof(size_t), possivelmente arredondado para o alinhamento correto. Em algumas máquinas essa constante tem um valor 4 ou 8. Esse não é um identificador real do C++ que será definido para o seu compilador.

    // Original code: Fred* p = new Fred[n];
    char* tmp = (char*) operator new[] (WORDSIZE + n * sizeof(Fred));
    Fred* p = (Fred*) (tmp + WORDSIZE);
    *(size_t*)tmp = n;
    size_t i;
    try {
      for (i = 0; i < n; ++i)
        new(p + i) Fred();           // Placement new
    } catch (...) {
      while (i-- != 0)
        (p + i)->~Fred();            // Explicit call to the destructor
      operator delete[] ((char*)p - WORDSIZE);
      throw;
    } 
O comando delete[] p torna-se então em:
    // Original code: delete[] p;
    size_t n = * (size_t*) ((char*)p - WORDSIZE);
    while (n-- != 0)
      (p + n)->~Fred();
    operator delete[] ((char*)p - WORDSIZE); 
Note que o endereço passado para operator delete[] não é o mesmo que p.

Comparada à técnica matriz associativa, esta técnica é mais veloz, porém mais sensível ao problema de programadores escreverem delete p ao invés de delete[] p. Por exemplo, se você cometer um erro de programação, escrevendo delete p onde você deveria escrever delete[] p, o endereço passado para o operator delete(void*) não será o endereço de qualquer localização válida da memória de alocação dinâmica. Isso provavelmente vai corromper os controles de memória. Bang. Você está morto.

Topo
[ 33.6 ] Como os compiladores usam matriz associativa para lembrar o número de elementos em uma matriz alocada dinamicamente?

Recorde-se de que quando você delete[] uma matriz, o sistema de execução sabe, como que por mágica, quantos destrutores executar. Essa FAQ descreve uma técnica usada por alguns compiladores C++ para conseguir isso. Uma outra ténica comum é over-allocate.

Se o compilador usa a técnica matriz associativa, o código para p = new Fred[n] como exemplo seguinte, onde arrayLengthAssociation é o nome imaginário de uma matriz associativa global, oculta, que mapeia de void* a size_t:

    // Original code: Fred* p = new Fred[n];
    Fred* p = (Fred*) operator new[] (n * sizeof(Fred));
    size_t i;
    try {
      for (i = 0; i < n; ++i)
        new(p + i) Fred();           // Placement new
    } catch (...) {
      while (i-- != 0)
        (p + i)->~Fred();            // Explicit call to the destructor
      operator delete[] (p);
      throw;
    }
    arrayLengthAssociation.insert(p, n); 
O comando delete[] p torna-se então em:
    // Original code: delete[] p;
    size_t n = arrayLengthAssociation.lookup(p);
    while (n-- != 0)
      (p + n)->~Fred();
    operator delete[] (p); 
Cfront usa essa técnica, utilizando uma árvore AVL para implementar a matriz associativa.

Comparada coma técnica over-allocation, a técnica matriz associativa é mais lenta, porém menos sensível ao problema de programadores escreverem delete p ao invés de delete[] p. Por exemplo, se você cometer um erro de programação escrevendo delete p, onde você deveria escrever delete[] p, apenas o primeiro Fred na matriz será destruído, mas a memória de alocação dinâmica vai sobreviver, a menos que você tenha substituído o operator delete[] por algo que simplesmente não invoca operator delete[], ou a menos que sejam necessários destrutores para outros objetos Fred

Topo
[ 33.7 ] Se name mangling fosse padronizado, eu poderia ligar códigos compilados com diferentes compiladores de diferentes fornecedores?

Resposta curta: provavelmente não.

Em outras palavras: algumas pessoas gostariam de ver padrões para name mangling incorporados à proposta de padronização C++ ANSI, numa tentativa de evitar ter que comprar diferentes versões de bibliotecas de classes para diferentes compiladores. Contudo, a diferença de name mangling é uma das menores diferenças entre as implementações de compiladores, mesmo quando para a mesma plataforma.

Aqui está uma lista parcial das outras diferenças:

  • Número e tipo de argumentos ocultos para funções membro
    • this é tratado de modo especial?
    • Onde é passado o pointer return-by-value?
  • Assumindo que uma v-table é usada:
    • Qual o seu conteúdo e o seu leiaute?
    • Onde/como é feito o ajuste para this em caso de herança múltipla ou virtual?
  • Como as classes são acomodadas, incluindo:
    • Localização das classes bases?
    • Manejo das classes bases virtual?
    • Localização de v-pointers, se forem usados?
  • Convenção de chamada para funções incluindo:
    • Onde os parâmetros reais são colocados?
    • Em que ordem os parâmetros reais são passados?
    • Como os registradores são salvos?
    • Onde vai o valor de retorno?
    • O chamador ou o chamado executa um pop na pilha após a chamada?
    • Regras especiais para passagem ou retorno de estruturas?
  • Como é acomodada a identificação de tipos em tempo de execução?
  • Como o sistema de tratamento de exceções de execução sabe quais os objetos locais que precisam ser destruídos durante a ocorrência de uma exceção?
Topo
[ 33.8 ] O compilador GNU C++ (g++) produz executáveis muito grandes para códigos fonte minúsculos. Porque?

ligb++ (a biblioteca usada pelo g++) provavelmente foi compilada com opção de debug information (-g). Em algumas máquinas, a simples recompilação de libg++ sem opção de debug pode economizar muito espaço em disco (aproximadamente 1MB); o lado negativo: você não terá como seguir a trilha das chamadas libg++. Meramente strip-ping o executável não tem um efeito tão grande quanto uma recompilação sem a opção -g seguida por strip-ping o resultante a.out's.

Use size a.out para verificar o quanto são realmente grandes o programa e os segmentos de dados, ao invés de ls -s a.out que inclui também a tabela de símbolos.

Topo
[ 33.9 ] A gramática yacc é compatível com C++?

Consta que a gramática yacc é bastante próxima do C++. Até onde estou informado, ela não foi atualizada com os padrões C++, Por exemplo, a gramática não trata templates, tratamento de exceções, nem identificação de tipos em tempo de execução, e desvia-se do restante da linguagem em alguns casos mais sutis.

A gramática yacc está disponível em http://srawgw.sra.co.jp/.a/pub/cmd/c++grammar2.0.tar.gz

Topo
[ 33.10 ] O que é C++ 1.2? 2.0? 2.1? 3.0?

Não propriamente versões da linguagem, ao contrário, são versões de cfront, que foi o primeiro tradutor para C++ implementado pela AT&T. Tornou-se aceito, de um modo genérico, usar os números de versões do cfront com se fossem identificadores de versões da própria linguagem.

Em termos muito gerais, os principais recursos dessas versões são:

  • 2.0 Inclui herança múltipla/virtual e funções virtual puras
  • 2.1 Inclui classes semi-aninhadas e detele[] pointerTo Array
  • 3.0 Inclui classes completamente aninhadas, templates e i++ vs ++i
  • 4.0 Inclui tratamento do exceções
Topo Anterior Próximo Índice
C++ FAQ Lite
Copyright © 1991-98 by Marshall Cline Ph.D., cline@parashift.com
Tradução: Dagoberto Haele Arnaut

| Home | Bookmarks | Universidades | Para Saber mais | Universidades | WEB Directory | Mapa do site |