Domanda

ho scritto il seguente programma C ++

class MyClass {
public:
        int i;
        int j;
        MyClass() {};
};

int main(void)
{
        MyClass inst;
        inst.i = 1;
        inst.j = 2;
}

e ho compilato.

# g++ program.cpp
# ls -l a.out
-rwxr-xr-x  1 root  wheel  4837 Aug  7 20:50 a.out

Poi, ho #included il file di intestazione iostream nel file di origine e ho compilato di nuovo.

# g++ program.cpp
# ls -l a.out
-rwxr-xr-x  1 root  wheel  6505 Aug  7 20:54 a.out

La dimensione del file, come previsto, è stato aumentato.

Ho anche scritto il seguente programma C

int main(void)
{
    int i = 1;
    int j = 2;
}

e ho compilato

# gcc program.c
# ls -l a.out
-rwxr-xr-x  1 root  wheel  4570 Aug  7 21:01 a.out

Poi, ho #included il file di intestazione stdio.h e ho compilato di nuovo

# gcc program.c
# ls -l a.out
-rwxr-xr-x  1 root  wheel  4570 Aug  7 21:04 a.out

Stranamente, le dimensioni dei file eseguibili rimasta la stessa.

È stato utile?

Soluzione

Con l'inclusione di iostream nel file sorgente, il compilatore ha bisogno di generare il codice per impostare e abbattere la libreria standard di I / O C ++. Si può vedere questo guardando l'output di nm, che mostra i simboli (funzioni generalmente) sul tuo file oggetto:

$ nm --demangle test_with_iostream
08049914 d _DYNAMIC
08049a00 d _GLOBAL_OFFSET_TABLE_
08048718 t global constructors keyed to main
0804883c R _IO_stdin_used
         w _Jv_RegisterClasses
080486d8 t __static_initialization_and_destruction_0(int, int)
08048748 W MyClass::MyClass()
         U std::string::size() const@@GLIBCXX_3.4
         U std::string::operator[](unsigned int) const@@GLIBCXX_3.4
         U std::ios_base::Init::Init()@@GLIBCXX_3.4
         U std::ios_base::Init::~Init()@@GLIBCXX_3.4
080485cc t std::__verify_grouping(char const*, unsigned int, std::string const&)
0804874e W unsigned int const& std::min<unsigned int>(unsigned int const&, unsigned int const&)
08049a3c b std::__ioinit
08049904 d __CTOR_END__
... (remaining output snipped) ...

(--demangle batte C ++ nomi di funzione "alterati" di dal compilatore e produce nomi più significativi. La prima colonna è l'indirizzo, se la funzione è incluso nel eseguibile. La seconda colonna è il tipo. "T" è il codice nel segmento "testo" "U" sono simboli legati da altri luoghi,.. in questo caso, dal C ++ libreria condivisa)

Confrontare questo con le funzioni generate dal file di origine senza includere iostream:

$ nm --demangle test_without_iostream
08049508 d _DYNAMIC
080495f4 d _GLOBAL_OFFSET_TABLE_
080484ec R _IO_stdin_used
         w _Jv_RegisterClasses
0804841c W MyClass::MyClass()
080494f8 d __CTOR_END__
... (remaining output snipped) ...

Quando il file sorgente incluso iostream, il compilatore ha generato diverse funzioni non presenti senza iostream.

Quando il file di origine include solo stdio.h, il binario generato è simile al test senza iostream, dal momento che il C standard di I / O libreria non ha bisogno di alcuna di inizializzazione in più al di là di ciò che sta già accadendo nella libreria dinamica C. Potete vedere questo, cercando in uscita nm, che è identica.

In generale, però, cercando di intuire le informazioni circa la quantità di codice generato da un particolare file sorgente in base alle dimensioni del file eseguibile non sta per essere significativo; c'è troppo che potrebbe cambiare, e le cose semplici come la posizione del file di origine potrebbe cambiare il binario se il compilatore include informazioni di debug.

È inoltre possibile trovare objdump utile per rovistando presso il contenuto dei file eseguibili.

Altri suggerimenti

I file header sono in genere solo dichiarazioni e non direttamente traducono in codice macchina generato. Il linker è sufficiente a non tirare in funzioni non utilizzate dal CRT, quindi basta compreso stdio.h senza l'utilizzo di una qualsiasi delle sue funzioni non si tradurrebbe in più di codice nel vostro eseguibile intelligente.

EDIT:. Possono includere funzioni inline, classi e così via che non includere il codice, ma quelli non dovrebbe comportare un aumento nella vostra dimensione eseguibile fino a quando non vengono effettivamente utilizzati

iostream include il codice. stdio.h non lo fa.

In particolare, le seguenti definizioni in iostream (ci sono più di elencato, e variano a seconda del compilatore) oggetti di riferimento creati nella libreria standard, che vengono poi collegati nel codice:

extern istream &cin;
extern ostream &cout;
extern ostream &cerr;
extern ostream &clog;

Ci sono alcune inizializzazioni statiche in iostream, mentre in stdio.h ci sono solo le funzioni e loro definizioni. Pertanto tra cui iostream produrrà eseguibile di dimensioni maggiori.

Generalmente parlando, i file di intestazione contengono solo informazioni per il compilatore, non il codice vero e proprio. Ad esempio:

struct foo {
  int x;
};

Definizioni struttura come quella appaiono spesso nelle intestazioni, ma in realtà non causano il codice da generare, in quanto solo dare le informazioni del compilatore su come gestire 'pippo', dovrebbe vedere in un secondo momento. Se non vede foo, le informazioni vengono perse quando la compilazione termina.

In realtà, avendo tutto ciò che fa generare il codice generalmente produrrà un errore. Ad esempio:

void foo() {
  printf("bar!\n");
}

Se questo è in un colpo di testa, e viene incluso in due file .c, la funzione foo() verrà generato due volte . Ciò causerà un errore al link. E 'possibile evitare l'errore, se si dispone di un forte motivo per farlo, ma il codice generalmente in realtà la generazione di intestazioni viene evitato, se possibile.

Si noti che una sola eccezione qui è membri in linea in C ++. Ad esempio:

class Foo {
  void bar() { /* ... */ }
};

Tecnicamente parlando bar () viene generato in ogni file che include questo codice. Il compilatore fa diversi accorgimenti per evitare l'errore (debole legame, ecc). Questo può effettivamente aumentare la dimensione del file eseguibile, ed è probabilmente quello che avete visto con <iostream>.

L'intestazione <iostream> viene fornito con un paio di oggetti, 'std :: cin, 'std::cout, std::cerr e std::clog. Queste sono istanze di classi che hanno costruttori non banali e distruttori. Questi sono il codice e devono essere collegati. Questo è ciò che aumenta la dimensione del file eseguibile.

Per quanto ne so, <cstdio> non viene fornito con il codice, è per questo che non c'è alcun aumento delle dimensioni dell'eseguibile.

file iostream dichiarato alcuni oggetti globali:

std :: cout, std :: cerr, std :: cin che sono di tipo ostream.

Quindi il compilatore porterà quella classe e compilarlo direttamente nel tuo binario finale, aggiungendo così tanto alla sua dimensione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top