resueltos - ¿Por qué los compiladores C y C++ colocan variables globales inicializadas explícitamente y por defecto en diferentes segmentos?
programas en c++ ejemplos avanzados (3)
Estaba leyendo esta excelente publicación sobre el diseño de la memoria de los programas C. Dice que las variables globales inicializadas predeterminadas residen en el segmento BSS , y si proporciona explícitamente un valor a una variable global, entonces residirá en el segmento de datos .
He probado los siguientes programas en C y C ++ para examinar este comportamiento.
#include <iostream>
// Both i and s are having static storage duration
int i; // i will be kept in the BSS segment, default initialized variable, default value=0
int s(5); // s will be kept in the data segment, explicitly initialized variable,
int main()
{
std::cout<<&i<<'' ''<<&s;
}
Salida:
0x488020 0x478004
Por lo tanto, desde la salida, parece claramente que ambas variables i y s residen en segmentos completamente diferentes. Pero si elimino el inicializador (valor inicial 5 en este programa) de la variable S y luego ejecuto el programa, me da el siguiente resultado.
Salida:
0x488020 0x488024
Entonces, desde el resultado, parece claramente que ambas variables i y s residen en el mismo segmento (en este caso, BSS).
Este comportamiento también es el mismo en C.
#include <stdio.h>
int i; // i will be kept in the BSS segment, default initialized variable, default value=0
int s=5; // s will be kept in the data segment, explicitly initialized variable,
int main(void)
{
printf("%p %p/n",(void*)&i,(void*)&s);
}
Salida:
004053D0 00403004
Entonces, de nuevo podemos decir mirando el resultado (significa examinar la dirección de las variables), ambas variables i y s residen en segmentos completamente diferentes. Pero nuevamente si elimino el inicializador (valor inicial 5 en este programa) de la variable S y luego ejecuto el programa, me da el siguiente resultado.
Salida:
004053D0 004053D4
Entonces, desde el resultado, parece claramente que ambas variables i y s residen en el mismo segmento (en este caso, BSS).
¿Por qué los compiladores C y C ++ colocan variables globales inicializadas explícitamente y por defecto en diferentes segmentos? ¿Por qué hay una distinción sobre dónde reside la variable global entre las variables inicializadas por defecto y las variables inicializadas explícitamente? Si no me equivoco, los estándares C y C ++ nunca hablan sobre la pila, el montón, el segmento de datos, el segmento de código, el segmento BSS y todos los aspectos específicos de la implementación. Entonces, ¿es posible que una implementación en C ++ almacene variables inicializadas y variables inicializadas explícitamente en los mismos segmentos en lugar de mantenerlo en diferentes segmentos?
La respuesta realmente corta es "porque ocupa menos espacio". (Como notaron otros, ¡el compilador no tiene que hacer esto!)
En el archivo ejecutable, la sección de data
contendrá datos que tienen su almacén de valores en el lugar correspondiente. Esto significa que por cada byte de datos inicializados, esa sección de datos contiene un byte.
Para variables globales inicializadas cero, no hay ninguna razón para almacenar muchos ceros. En su lugar, simplemente almacene el tamaño de todo el conjunto de datos en un solo tamaño-valor. Por lo tanto, en lugar de almacenar 4132 bytes de cero en el sector de data
, solo hay un "BSS con 4132 bytes de longitud", y depende del OS / runtime configurarlo para que sea cero. - en algunos casos, el tiempo de ejecución del compilador será memset(BSSStart, 0, BSSSize)
o similar. En, por ejemplo, Linux, toda la memoria "no utilizada" se llena de cero de todos modos cuando se crea el proceso, por lo que establecer BSS en cero es solo una cuestión de asignar la memoria en primer lugar.
Y, por supuesto, los archivos ejecutables más cortos tienen varias ventajas: menos espacio en su disco duro, mayor tiempo de carga [extra extra si el SO llena previamente la memoria asignada con cero], tiempo de compilación más rápido que el compilador / enlazador no lo hace t tiene que escribir los datos en el disco.
Entonces, hay una razón completamente práctica para esto.
Ni el lenguaje C ni C ++ tienen ninguna noción de "segmentos", y tampoco todos los sistemas operativos lo hacen, por lo que su pregunta depende inevitablemente de la plataforma y el compilador.
Dicho esto, las implementaciones comunes tratarán las variables inicializadas frente a las no inicializadas de forma diferente. La principal diferencia es que los datos no inicializados (o inicializados por defecto) no tienen que guardarse realmente con el módulo compilado, sino que solo se declaran / reservan para su uso posterior en tiempo de ejecución. En términos prácticos de "segmento", los datos inicializados se guardan en el disco como parte del binario, mientras que los datos no inicializados no , en cambio se asignan al inicio para satisfacer las "reservas" declaradas.
Por definición, BSS no es un segmento diferente, es una parte del segmento de datos.
En C y C ++, los objetos asignados estáticamente sin un inicializador explícito se inicializan a cero, una implementación también puede asignar variables y constantes asignadas estáticamente inicializadas con un valor que consiste únicamente en bits de valor cero para la sección BSS .
Una razón para almacenarlos en BSS es que esos tipos de variables con valores no inicializados o por defecto se pueden obtener en tiempo de ejecución sin perder espacio en los archivos binarios en lugar de las variables que se colocan en el segmento de datos.