Pregunta

Tengo mucha curiosidad por la organización de la memoria de la pila después de experimentar lo que sucede en segundo plano y obviamente vi que coincide con el pequeño conocimiento que adquirí de los libros.Sólo quería comprobar si lo que he entendido es correcto.

Tengo un programa fundamental: tiene 2 funciones, la primera es foo y la otra es principal (el punto de entrada).

void foo(){
    // do something here or dont
}

int main(){

    int i = 0;

    printf("%p %p %p\n",foo, &i, main);

    system("PAUSE");
    return EXIT_SUCCESS;
};

La salida del programa se muestra a continuación, la variable local i de main está ubicada totalmente en una posición no relacionada.integer es un tipo de valor, pero lo verificó nuevamente con un puntero char * local a main y obtuvo resultados similares.

00401390 0022FF44 00401396
Press any key to continue . . .

Entiendo principalmente que el código y las variables se asignan en diferentes segmentos de memoria (segmento de código/segmento de datos).Básicamente, ¿es correcto decir que la pila de llamadas colapsa la información básica sobre la ejecución de funciones (sus variables locales, parámetros, puntos de retorno) y la mantiene en el segmento de datos?

¿Fue útil?

Solución

Una pequeña advertencia al comienzo: todas estas respuestas están algo afectadas por el sistema operativo y la arquitectura del hardware. Windows hace las cosas de manera bastante diferente a los lenguajes similares a UNIX, sistemas operativos en tiempo real y UNIX de sistema pequeño antiguo.

Pero la respuesta básica como han dicho @Richie y @Paul es " yes. " Cuando el compilador y el enlazador terminan con el código, se divide en lo que se conoce como & Quot; text & Quot; y " datos " segmentos en UNIX. Un segmento de texto contiene instrucciones y algunos tipos de datos estáticos; un segmento de datos contiene, bueno, datos.

Se asigna una gran parte del segmento de datos para la pila y el espacio de almacenamiento dinámico. Se pueden asignar otros fragmentos a elementos como estructuras de datos estáticas o externas.

Entonces, sí, cuando se ejecuta el programa, el contador del programa está ocupando las instrucciones de un segmento diferente al de los datos. Ahora nos adentramos en algunas dependencias de la arquitectura, pero en general, si tiene memoria segmentada, sus instrucciones se construyen de tal manera que la obtención de un byte de los segmentos es lo más eficiente posible. En la antigua arquitectura 360, tenían registros base , en x86 tengo un montón de pelo que creció a medida que el espacio de direcciones pasaba a los 8080 antiguos a los procesadores modernos, pero todas las instrucciones están optimizadas con mucho cuidado porque, como puedes imaginar, buscar instrucciones y sus operandos son muy de uso intensivo.

Ahora utilizamos arquitecturas más modernas con memoria virtual y unidad de administración de memoria s. Ahora la máquina tiene un hardware específico que permite que el programa trate el espacio de direcciones como un gran rango plano de direcciones; los diversos segmentos simplemente se colocan en ese espacio virtual de direcciones de bits. El trabajo de la MMU es tomar una dirección virtual y traducirla a una dirección física, incluido qué hacer si esa dirección virtual no está en la memoria física en este momento. Nuevamente, el hardware MMU está muy optimizado, pero eso no significa que haya ningún costo de rendimiento asociado. Pero a medida que los procesadores se han vuelto más rápidos y los programas se han hecho más grandes, se ha vuelto cada vez menos importante.

Otros consejos

Sí, eso es exactamente correcto. El código y los datos viven en diferentes partes de la memoria, con diferentes permisos. La pila contiene parámetros, direcciones de retorno y variables locales (& Quot; automáticas & Quot;), y vive con los datos.

Sí.

Imagine que su memoria de código es ROM, y su memoria de datos es RAM (una arquitectura común de chip pequeño). Luego verá que la pila debe estar en la memoria de datos.

Bueno, puedo hablar en nombre de SPARC:

Sí.Cuando ejecuta el programa, el programa se lee dos veces (al menos en SPARC).El programa se carga en la memoria y luego se cargan las asignaciones de matriz/pila.En el segundo paso por el programa, las pilas se asignan a una memoria separada.

No estoy seguro de los procesadores basados ​​en CISC, pero sospecho que no varía demasiado.

Su programa exhibe un comportamiento indefinido específicamente porque:

  • no incluyes <stdio.h> o <cstdio> dependiendo del idioma en el que estés compilando tu código
  • printf y todas las funciones de argumentos variables no tienen la capacidad de verificar el tipo de sus argumentos.Por lo tanto, es obligatorio por su parte pasar los argumentos escritos correctamente.Realmente deberías hacer:
  • system() no tiene declaración en su alcance.Incluir <stdlib.h> o <cstdlib> según el caso puede ser.

Escribe tu código como:

   #include <stdio.h>

   int main() {
      /* ... */
      printf("%p %p %p\n", (void *)foo, (void *)&i, (void *)main);
      /* ... */
   }

También tenga en cuenta que:

  • La definición de void foo() No es un prototipo en C, sino en C++.Sin embargo, si escribieras void foo(void) Obtendrías un prototipo en ambos idiomas.
  • system() depende de la implementación: es posible que su código no se comporte como se espera en todas las plataformas.

El lenguaje propiamente dicho (C o C++) no impone ninguna restricción sobre cómo organizar la memoria.Ni siquiera tiene el concepto de pila o montón.Estos se definen mediante implementaciones que consideren adecuadas.Lo ideal sería consultar la documentación proporcionada por su implementación para tener una idea clara de lo que hacen.

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