Teniendo en cuenta que la memoria se divide en cuatro segmentos: datos, montón, pila y código, donde las variables globales, variables estáticas, tipos de datos constantes, variables locales (definidas y declaradas en funciones), variables (en función principal), punteros y el espacio asignado dinámicamente (usando malloc y calloc) se almacena en la memoria
Creo que se asignarían de la siguiente manera:
- Variables globales -------> datos
- Variables estáticas -------> datos
- Tipos de datos constantes -----> código
- Variables locales (declaradas y definidas en funciones) --------> stack
- Variables declaradas y definidas en la función principal -----> montón
- Punteros (por ejemplo
char *arr,int *arr) -------> montón - Espacio asignado dinámicamente (usando malloc y calloc) --------> stack
Me refiero a estas variables solo desde la perspectiva C.
Corríjame si me equivoco, ya que soy nuevo en C.
c
memory
memory-management
types
starkk92
fuente
fuente

mainEs solo otra función. Las variables van a la pila a menos que seamalloccomo en cualquier otro lado.Respuestas:
Has acertado algunos de estos, pero quien escribió las preguntas te engañó en al menos una pregunta:
mainfunción ----->montóntambién se apilan (el profesor intentaba engañarte)char *arr,int *arr) ------->montónde datos o pila, dependiendo del contexto. C le permite declarar unstaticpuntero global o , en cuyo caso el puntero en sí mismo terminaría en el segmento de datos.malloc,calloc,realloc) -------->pilamontónVale la pena mencionar que "stack" se llama oficialmente "clase de almacenamiento automático".
fuente
allocaque funciona de manera similarmalloc, pero sí la asignación de la pila.Para aquellos futuros visitantes que puedan estar interesados en conocer esos segmentos de memoria, estoy escribiendo puntos importantes sobre 5 segmentos de memoria en C:
Algunos jefes:
5 segmentos de memoria en C:
1. Segmento de código
printf("Hello, world"), la cadena "Hola, mundo" se crea en el segmento de código / texto. Puede verificar esto usando elsizecomando en el sistema operativo Linux.Segmento de datos
El segmento de datos se divide en las dos partes siguientes y, por lo general, se encuentra debajo del área de almacenamiento dinámico o en algunas implementaciones por encima de la pila, pero el segmento de datos nunca se encuentra entre el área de almacenamiento dinámico y la pila.
2. Segmento de datos no inicializado
int globalVar;o variable local estáticastatic int localStatic;se almacenarán en el segmento de datos no inicializados.0oNULLentonces, iría al segmento de datos no inicializado o bss.3. Segmento de datos inicializado
int globalVar = 1;o la variable local estáticastatic int localStatic = 1;se almacenarán en el segmento de datos inicializado.4. Segmento de pila
5. Segmento del montón
malloc,callocoreallocmétodos.int* prt = malloc(sizeof(int) * 2)se asignarán ocho bytes en el montón y la dirección de memoria de esa ubicación se devolverá y almacenará enptrvariable. Laptrvariable estará en la pila o en el segmento de datos dependiendo de la forma en que se declare / use.fuente
Corregí tus oraciones incorrectas
variables constantes locales -----> stack
variable constante global inicializada -----> segmento de datos
variable constante global no inicializada -----> bss
variables declaradas y definidas en la función principal -----> stack
punteros (ej .: char * arr, int * arr) -------> el tamaño de esa variable de puntero estará en la pila.
Considere que está asignando memoria de n bytes (usando
mallococalloc) dinámicamente y luego haciendo una variable de puntero para apuntarlo. Ahora que losnbytes de memoria están en el montón y la variable de puntero requiere 4 bytes (si la máquina de 64 bits es de 8 bytes) que estarán en la pila para almacenar el puntero inicial de losnbytes de la porción de memoria.Nota: Las variables de puntero pueden apuntar la memoria de cualquier segmento.
espacio asignado dinámicamente (usando malloc, calloc) --------> montón
fuente
Una arquitectura de escritorio popular divide la memoria virtual de un proceso en varios segmentos :
Segmento de texto: contiene el código ejecutable. El puntero de instrucción toma valores en este rango.
Segmento de datos: contiene variables globales (es decir, objetos con enlace estático). Subdividido en datos de solo lectura (como constantes de cadena) y datos no inicializados ("BSS").
Segmento de pila: contiene la memoria dinámica para el programa, es decir, la tienda libre ("montón") y los marcos de pila locales para todos los hilos. Tradicionalmente, la pila C y la pila C solían crecer en el segmento de pila desde los extremos opuestos, pero creo que la práctica se ha abandonado porque es demasiado insegura.
El programa AC generalmente coloca objetos con una duración de almacenamiento estático en el segmento de datos, objetos asignados dinámicamente en el almacén gratuito y objetos automáticos en la pila de llamadas del hilo en el que vive.
En otras plataformas, como el antiguo modo real x86 o en dispositivos integrados, las cosas obviamente pueden ser radicalmente diferentes.
fuente
Desde la perspectiva del lenguaje C , todo lo que importa es la extensión, el alcance, la vinculación y el acceso; exactamente cómo se asignan los elementos a diferentes segmentos de memoria depende de la implementación individual, y eso variará. El lenguaje estándar no habla sobre segmentos de memoria en absoluto . La mayoría de las arquitecturas modernas actúan principalmente de la misma manera; las variables de alcance de bloque y los argumentos de función se asignarán desde la pila, el alcance de archivo y las variables estáticas se asignarán desde un segmento de datos o código, la memoria dinámica se asignará desde un montón, algunos datos constantes se almacenarán en segmentos de solo lectura etc.
fuente
Una cosa que hay que tener en cuenta sobre el almacenamiento es la regla como si . No se requiere que el compilador coloque una variable en un lugar específico; en su lugar, puede colocarla donde lo desee, siempre que el programa compilado se comporte como si se ejecutara en la máquina C abstracta de acuerdo con las reglas de la máquina C abstracta. Esto se aplica a todas las duraciones de almacenamiento . Por ejemplo:
42en el código de ensamblado generado pero sin signos de404.constoconstno necesita estar en la memoria. Ejemplo : el compilador puede demostrar quefooes efectivoconste integra su uso en el código.bartiene enlace externo y el compilador no puede probar que no se cambiaría fuera del módulo actual, por lo tanto, no está en línea.mallocno necesita residir en la memoria asignada desde el montón! Ejemplo : observe cómo el código no tiene una llamadamallocy tampoco se almacena el valor 42 en la memoria, ¡se guarda en un registro!mallocy la referencia se pierde sin desasignar el objeto sinfreenecesidad de perder memoria ...mallocno necesita estar dentro del montón debajo del salto de programa (sbrk(0)) en Unixen ...fuente
No, pueden estar en la pila o en el segmento de datos. Pueden apuntar a cualquier parte.
fuente
mainy variables dinámicamente asignados son demasiado malfuente
Ejemplos ejecutables mínimos de Linux con análisis de desmontaje
Dado que este es un detalle de implementación no especificado por los estándares, echemos un vistazo a lo que está haciendo el compilador en una implementación particular.
En esta respuesta, vincularé a respuestas específicas que hacen el análisis, o proporcionaré el análisis directamente aquí, y resumiré todos los resultados aquí.
Todos ellos están en varias versiones de Ubuntu / GCC, y los resultados son probablemente bastante estables en todas las versiones, pero si encontramos alguna variación, especifiquemos versiones más precisas.
Variable local dentro de una función
Ya sea
maino cualquier otra función:Como se muestra en: ¿Qué significa <valor optimizado fuera> en gdb?
-O0: apilar-O3: registra si no se derraman, apilar de otra maneraPara obtener motivación sobre por qué existe la pila, consulte: ¿Cuál es la función de las instrucciones push / pop utilizadas en los registros en el ensamblaje x86?
Variables globales y
staticvariables de función0o no inicializa (y, por lo tanto, se inicializa implícitamente0):.bsssección, vea también: ¿Por qué se requiere el segmento .bss?.datasecciónchar *ychar c[]Como se muestra en: ¿Dónde se almacenan las variables estáticas en C y C ++?
¿TODO también se colocarán literales de cadena muy grandes en la pila? O
.data? ¿O falla la compilación?Argumentos de la función
Debe pasar por la convención de llamada relevante, por ejemplo: https://en.wikipedia.org/wiki/X86_calling_conventions para X86, que especifica registros específicos o ubicaciones de pila para cada variable.
Entonces, como se muestra en ¿Qué significa <valor optimizado fuera> en gdb? ,
-O0luego sorbe todo en la pila, mientras-O3trata de usar registros tanto como sea posible.Sin embargo, si la función se alinea, se tratan como locales normales.
constCreo que no hay diferencia porque puedes descartarlo.
Por el contrario, si el compilador puede determinar que algunos datos nunca se escriben, en teoría podría colocarlos en
.rodataincluso si no son constantes.TODO análisis.
Punteros
Son variables (que contienen direcciones, que son números), igual que todas las demás :-)
malloc
La pregunta no tiene mucho sentido para
malloc, ya quemalloces una función, y en:*ies una variable que contiene una dirección, por lo que corresponde al caso anterior.En cuanto a cómo funciona malloc internamente, cuando lo llama, el kernel de Linux marca ciertas direcciones como grabables en sus estructuras de datos internas, y cuando el programa las toca inicialmente, ocurre una falla y el kernel habilita las tablas de páginas, lo que permite el acceso suceder sin segfaul: ¿Cómo funciona la paginación x86?
Sin embargo, tenga en cuenta que esto es básicamente exactamente lo que hace el
execsyscall debajo del capó cuando intenta ejecutar un ejecutable: marca las páginas en las que desea cargar y escribe el programa allí, vea también: ¿Cómo obtiene el núcleo un archivo binario ejecutable que se ejecuta bajo linux? Excepto queexectiene algunas limitaciones adicionales sobre dónde cargar (por ejemplo, si el código no es reubicable ).La syscall exacta utilizada
malloces parammapimplementaciones modernas de 2020, y en el pasadobrkse usaba: ¿malloc () usa brk () o mmap ()?Bibliotecas dinámicas
Básicamente,
mmapvaya a la memoria: /unix/226524/what-system-call-is-used-to-load-libraries-in-linux/462710#462710variables del entorno y
main'sargvArriba de la pila inicial: /unix/75939/where-is-the-environment-string-actual-stored TODO ¿por qué no en .data?
fuente