Pregunta

escribí el siguiente programa en C ++

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

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

y compilé.

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

A continuación, me #included la iostream archivo de cabecera en el archivo de origen y que compilan de nuevo.

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

El tamaño del archivo, como se esperaba, se incrementó.

También escribí el siguiente programa C

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

y compilé

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

A continuación, me #included el archivo de cabecera stdio.h y compilé nuevo

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

Por extraño que parezca, el tamaño de los archivos ejecutables siendo los mismos.

¿Fue útil?

Solución

Al incluir iostream en el archivo de origen, el compilador tiene que generar código de configurar y derribar la biblioteca de C ++ estándar de E / S. Esto se puede ver observando la salida de nm, que muestra los símbolos (generalmente funciona) en su archivo de objeto:

$ 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 toma el C ++ nombres de función "destrozados" por el compilador y produce nombres más significativos. La primera columna es la dirección, si la función está incluido en el ejecutable. La segunda columna es el tipo. "T" es código en el "texto" segmento "U" son símbolos vinculados en de otros lugares;.. en este caso, a partir de la biblioteca de C ++ compartido)

Compárese esto con las funciones generadas a partir de su archivo de origen sin incluir 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) ...

Cuando el archivo de origen incluye iostream, el compilador genera varias funciones que no están presentes sin iostream.

Cuando el archivo de origen incluye sólo stdio.h, el binario generado es similar a la prueba sin iostream, ya que la norma C biblioteca E / S no necesita ninguna inicialización extra por encima y más allá de lo que ya está sucediendo en la biblioteca dinámica C. Se puede ver esto mirando la salida nm, que es idéntica.

En general, sin embargo, tratando de intuir información acerca de la cantidad de código generado por un archivo fuente en particular en función del tamaño del ejecutable no va a ser significativo; hay demasiado que podría cambiar, y las cosas simples, como la ubicación del archivo de origen puede cambiar el binario si el compilador incluye información de depuración.

También puede encontrar objdump útil para hurgar en el contenido de sus archivos ejecutables.

Otros consejos

Los archivos de cabecera son típicamente sólo declaraciones y no resultan directamente en código máquina que se está generando. El enlazador es suficiente para no tirar en funciones no utilizados del CRT, por lo que sólo incluyendo stdio.h sin necesidad de utilizar cualquiera de sus funciones no se traduciría en más código ejecutable en su inteligente.

EDIT:. Pueden incluir funciones en línea, clases y así sucesivamente que no incluya el código, pero los que no deben dar lugar a un aumento en el tamaño del ejecutable hasta que se utilizan en realidad

iostream incluye código. stdio.h no lo hace.

Más específicamente, las siguientes definiciones en iostream (hay más de la lista, y varían según el compilador) objetos de referencia creado en la biblioteca estándar, que luego están vinculados en el código:

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

Hay algunas inicializaciones estáticas en iostream, mientras que en stdio.h sólo hay funciones y definiciones. Por lo tanto incluyendo iostream producirá ejecutable de mayor tamaño.

Generalmente hablando, los archivos de cabecera contienen sólo información para el compilador, no código real. Por ejemplo:

struct foo {
  int x;
};

Definiciones de estructuras como que a menudo aparecen en los encabezados, pero en realidad no causa código que se genera, ya que sólo dan la información compilador acerca de cómo manejar 'foo', en caso de verlo más tarde. Si no ve foo, la información se pierde cuando la compilación termina.

De hecho, tener nada que hace Generar código generalmente producirá un error. Por ejemplo:

void foo() {
  printf("bar!\n");
}
Si esto es en una cabecera, y se incluye en dos archivos .c, se generará

la función foo() dos veces . Esto causará un error en el enlace. Es posible evitar el error si tiene una razón de peso para hacerlo, pero el código que genera generalmente en realidad en las cabeceras se evita si es posible.

Tenga en cuenta que una excepción aquí es miembros en línea en C ++. Por ejemplo:

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

Técnicamente hablando bar () se genera en cada archivo que incluye este código. El compilador hace varios trucos para evitar el error (débil unión, etc.). Este hecho puede aumentar el tamaño del ejecutable, y es probablemente lo que viste con <iostream>.

La cabecera <iostream> viene con un par de objetos, 'std :: cin, 'std::cout, std::cerr y std::clog. Estos son instancias de clases que tienen constructores no triviales y destructores. Estos son de código y tienen que estar vinculados. Esto es lo que aumenta el tamaño del ejecutable.

Que yo sepa, <cstdio> no viene con el código, así que por eso no hay aumento en el tamaño del ejecutable.

archivo iostream declarado algunos objetos globales:

std :: cout, std :: cerr, std :: cin que son tipo ostream.

A continuación, el compilador traerá esa clase y compilar la derecha en su binario final, añadiendo tanto a su tamaño.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top