2010-01-30 18 views
8

Sto cercando di risolvere automaticamente typedefs in arbitrari progetti C++ o C.Risoluzione dei typedef in C e C++

Poiché alcuni dei typedef sono definiti nei file di intestazione di sistema (ad esempio uint32), sto cercando di ottenere questo risultato eseguendo il preprocessore gcc sui miei file di codice e quindi eseguendo la scansione dei file preelaborati per typedef. Dovrei quindi essere in grado di sostituire i typedef nei file di codice del progetto.

Mi chiedo, se c'è un altro, forse un modo più semplice, mi manca. Puoi pensarci?

Il motivo, perché voglio farlo: sto estraendo le metriche del codice dai progetti C/C++ con strumenti diversi. Le metriche sono basate sui metodi. Dopo aver estratto le metriche, devo unire i dati, che sono prodotti dai diversi strumenti. Il problema è che uno degli strumenti risolve typedef e altri no. Se ci sono typedef usati per i tipi di parametri dei parametri, ho metriche mappate su diversi nomi di metodi, che in realtà si riferiscono allo stesso metodo nel codice sorgente.

pensi di questo metodo nel codice sorgente: int test(uint32 par1, int par2)
Dopo aver eseguito i miei attrezzi ho metriche, mappate ad un metodo chiamato int test(uint32 par1, int par2) e alcuni dei miei parametri sono mappati a int test(unsigned int par1, int par2).

+5

Puoi anche fornire alcune informazioni sul motivo per cui è necessario rimuovere questi typedef dal codice? Probabilmente, questo ti aiuterà a suggerire una soluzione. – Jay

risposta

5

Se non ti interessa capire dove sono definiti, puoi usare objdump per scaricare la tabella dei simboli C++ che risolve i typedef.

lorien$ objdump --demangle --syms foo 

foo:  file format mach-o-i386 

SYMBOL TABLE: 
00001a24 g  1e SECT 01 0000 .text dyld_stub_binding_helper 
00001a38 g  1e SECT 01 0000 .text _dyld_func_lookup 
... 
00001c7c g  0f SECT 01 0080 .text foo::foo(char const*) 
... 

Questo frammento dalla seguente definizione di struttura:

typedef char const* c_string; 
struct foo { 
    typedef c_string ntcstring; 
    foo(ntcstring s): buf(s) {} 
    std::string buf; 
}; 

Ciò richiede che si compila tutto e sarà solo mostrare simboli nella eseguibile risultante quindi ci sono alcune limitazioni.L'altra opzione è fare in modo che il linker scarichi una mappa dei simboli. Per gli strumenti GNU aggiungere -Wl,-map e -Wl,name dove name è il nome del file da generare (vedere nota). Questo approccio non smentisce i nomi, ma con un po 'di lavoro è possibile decodificare le convenzioni di maneggevolezza del compilatore. L'output dal frammento precedente comprenderà qualcosa di simile:

0x00001CBE 0x0000005E [ 2] __ZN3fooC2EPKc 
0x00001D1C 0x0000001A [ 2] __ZN3fooC1EPKc 

È possibile decodificare questi utilizzando la specifica C++ ABI. Una volta che ti senti a tuo agio con come funziona, lo mangling table incluso con l'ABI diventa inestimabile. La derivazione in questo caso è:

<mangled-name>   ::= '_Z' <encoding> 
<encoding>    ::= <name> <bare-function-type> 
    <name>     ::= <nested-name> 
    <nested-name>  ::= 'N' <source-name> <ctor-dtor-name> 'E' 
     <source-name>  ::= <number> <identifier> 
     <ctor-dtor-name> ::= 'C2' # base object constructor 
    <bare-function-type> ::= <type>+ 
     <type>    ::= 'P' <type> # pointer to 
     <type>   ::= <cv-qualifier> <type> 
      <cv-qualifier> ::= 'K' # constant 
      <type>  ::= 'c' # character 

Nota: sembra GNU cambia gli argomenti ld quindi si consiglia di controllare il vostro manuale locale (man ld) per fare in modo che i comandi di generazione di file mappa sono -mapfilename nella tua versione. Nelle versioni recenti, use -Wl,-M and redirect stdout to a file.

+0

Quando provo a eseguire il mio compilatore in questo modo: 'g ++ foo.cpp -Wl, -map -Wl, mapname' ottengo l'errore'/usr/bin/ld: modalità di emulazione non riconosciuta: ap Emulazioni supportate: elf_i386 i386linux' . Sto usando i parametri correttamente? (versione g ++: 4.4.2 20091208 (pre-release), versione ld: 2.20.0.20091101) – Customizer

+0

Ho aggiornato la mia risposta. La mia versione locale è ancora alla 4.0.1 e sembra che gli argomenti siano cambiati. Prova 'g ++ foo.cpp -Wl, -M> foo.map'. –

+1

Il programma C++ filt può essere usato per demangling dei nomi. – Tronic

2

GCC-XML può aiutare con risolvere i typedef, dovreste seguire le tipo-ids di <Typedef> elementi fino a quando li ha deliberato di un elemento <FundamentalType>, <Struct> o <Class>.

Per sostituire i typedef nel progetto, tuttavia, si tratta di un problema più fondamentale: non è possibile cercare e sostituire semplicemente come si dovrebbe rispettare l'ambito dei nomi: si pensi ad es. funzioni typedef locali, alias dei nomi o direttive using.

A seconda di cosa stai effettivamente cercando di raggiungere, ci deve essere un modo migliore.

Aggiornamento: In realtà, nel contesto dato di fissare i dati delle metriche, la sostituzione dei nomi di battitura utilizzando gcc-xml dovrebbe funzionare correttamente se supporta il codice base.

+0

Non ne sono sicuro, ma penso che GCC-XML in realtà non sia più sviluppato attivamente. L'ultima versione ufficiale è, secondo il sito web, dal 2004. E se ricordo male, la versione CVS è basata solo su alcune versioni 3.x di gcc. Non lo so davvero, se questo è importante, comunque. Hmm, namespace. Non ci avevo ancora pensato, ad essere onesti. Questo complica la faccenda ... – Customizer

+0

Pensavo intendessi sostituire i tipi nella fonte, che sarebbe diventato più complicato. Se hai solo bisogno di correggere i dati delle metriche e non la fonte, gcc-xml dovrebbe essere sufficiente se supporta il tuo codice base. –

+0

In realtà, penso che i progetti, sto analizzando, dovrebbero essere tutti compilabili da un vcc gcc 3.x. Quindi questo potrebbe funzionare. – Customizer

3

È possibile utilizzare Clang (il front-end del compilatore LLVM C/C++) per analizzare il codice in modo da preservare le informazioni su typedef e persino macro. Ha una API C++ molto bella per leggere i dati dopo che il codice sorgente è stato letto nell'AST (abstract syntax tree). http://clang.llvm.org/

Se invece stai cercando un programma semplice che già risolva il problema per te (invece dell'API di programmazione Clang), penso che tu sia sfortunato, perché non ho mai visto una cosa del genere.

+0

Ho pensato che il parser C++ non è completo? –

+0

La generazione del codice è abbastanza incompleta, ma può già gestire la maggior parte della libreria standard, così come molte librerie esterne. Il parser è più completo, ma manca ancora alcune cose (quindi non puoi usarlo, ad es. Con Boost Spirit.Qi). Tuttavia, penso che potrebbe essere la migliore opzione disponibile per ciò che chiede il Customizer. – Tronic

+0

L'API sembra davvero eccezionale. Sono abbastanza curioso di provarlo quando è diventato stabile. –