variable todas tipos parametros las funciones estaticas creacion con c++ c compiler-construction

todas - ¿Dónde se almacenan las variables estáticas(en C/C++)?



variable static java (17)

¿En qué segmento (.BSS, .DATA, otro) de un archivo ejecutable se almacenan variables estáticas para que no tengan colisión de nombres? Por ejemplo:

foo.c: bar.c: static int foo = 1; static int foo = 10; void fooTest() { void barTest() { static int bar = 2; static int bar = 20; foo++; foo++; bar++; bar++; printf("%d,%d", foo, bar); printf("%d, %d", foo, bar); } }

Si compilo ambos archivos y lo vinculo a un main que llama a fooTest () y barTest repetidamente, las instrucciones de printf se incrementan de manera independiente. Tiene sentido ya que las variables foo y bar son locales a la unidad de traducción.

Pero, ¿dónde se asigna el almacenamiento?

Para ser claros, la suposición es que tienes una cadena de herramientas que daría salida a un archivo en formato ELF. Por lo tanto, creo que debe haber un espacio reservado en el archivo ejecutable para esas variables estáticas.
Para fines de discusión, supongamos que usamos la cadena de herramientas GCC.


Así es como (fácil de entender):


Bueno, esta pregunta es demasiado antigua, pero como nadie señala ninguna información útil: revise la publicación por ''mohit12379'' explicando la tienda de variables estáticas con el mismo nombre en la tabla de símbolos: http://www.geekinterview.com/question_details/24745


Cuando un programa se carga en la memoria, se organiza en diferentes segmentos. Uno de los segmentos es el segmento de DATOS . El segmento de datos se subdivide en dos partes:

Segmento de datos inicializado: todos los datos globales, estáticos y constantes se almacenan aquí.
Segmento de datos no inicializados (BSS): todos los datos no inicializados se almacenan en este segmento.

Aquí hay un diagrama para explicar este concepto:


Aquí hay un enlace muy bueno que explica estos conceptos:

http://www.inf.udec.cl/~leo/teoX.pdf


De hecho, una variable es tupla (almacenamiento, alcance, tipo, dirección, valor):

storage : where is it stored, for example data, stack, heap... scope : who can see us, for example global, local... type : what is our type, for example int, int*... address : where are we located value : what is our value

El alcance local podría significar local para la unidad de traducción (archivo de origen), la función o el bloque dependiendo de dónde esté definido. Para que la variable sea visible para más de una función, definitivamente tiene que estar en DATA o en el área BSS (dependiendo de si se inicializó explícitamente o no, respectivamente). Entonces se delimita de acuerdo con todas las funciones o funciones dentro del archivo fuente.


Depende de la plataforma y el compilador que esté utilizando. Algunos compiladores almacenan directamente en el segmento de código. Las variables estáticas siempre son accesibles solo para la unidad de traducción actual y los nombres no se exportan, por lo que las colisiones de nombres de razón nunca se producen.


La respuesta puede muy bien depender del compilador, por lo que probablemente desee editar su pregunta (es decir, incluso la noción de segmentos no es un mandato de ISO C ni ISO C ++). Por ejemplo, en Windows, un ejecutable no tiene nombres de símbolos. Un ''foo'' se compensaría 0x100, el otro quizás 0x2B0, y el código de ambas unidades de traducción se compilará conociendo las compensaciones para "su" foo.


La ubicación de almacenamiento de los datos dependerá de la implementación.

Sin embargo, el significado de estática es "vinculación interna". Por lo tanto, el símbolo es interno a la unidad de compilación (foo.c, bar.c) y no se puede hacer referencia fuera de esa unidad de compilación. Entonces, no puede haber colisiones de nombres.


Lo intenté con objdump y gdb, aquí está el resultado que obtengo:

(gdb) disas fooTest Dump of assembler code for function fooTest: 0x000000000040052d <+0>: push %rbp 0x000000000040052e <+1>: mov %rsp,%rbp 0x0000000000400531 <+4>: mov 0x200b09(%rip),%eax # 0x601040 <foo> 0x0000000000400537 <+10>: add $0x1,%eax 0x000000000040053a <+13>: mov %eax,0x200b00(%rip) # 0x601040 <foo> 0x0000000000400540 <+19>: mov 0x200afe(%rip),%eax # 0x601044 <bar.2180> 0x0000000000400546 <+25>: add $0x1,%eax 0x0000000000400549 <+28>: mov %eax,0x200af5(%rip) # 0x601044 <bar.2180> 0x000000000040054f <+34>: mov 0x200aef(%rip),%edx # 0x601044 <bar.2180> 0x0000000000400555 <+40>: mov 0x200ae5(%rip),%eax # 0x601040 <foo> 0x000000000040055b <+46>: mov %eax,%esi 0x000000000040055d <+48>: mov $0x400654,%edi 0x0000000000400562 <+53>: mov $0x0,%eax 0x0000000000400567 <+58>: callq 0x400410 <printf@plt> 0x000000000040056c <+63>: pop %rbp 0x000000000040056d <+64>: retq End of assembler dump. (gdb) disas barTest Dump of assembler code for function barTest: 0x000000000040056e <+0>: push %rbp 0x000000000040056f <+1>: mov %rsp,%rbp 0x0000000000400572 <+4>: mov 0x200ad0(%rip),%eax # 0x601048 <foo> 0x0000000000400578 <+10>: add $0x1,%eax 0x000000000040057b <+13>: mov %eax,0x200ac7(%rip) # 0x601048 <foo> 0x0000000000400581 <+19>: mov 0x200ac5(%rip),%eax # 0x60104c <bar.2180> 0x0000000000400587 <+25>: add $0x1,%eax 0x000000000040058a <+28>: mov %eax,0x200abc(%rip) # 0x60104c <bar.2180> 0x0000000000400590 <+34>: mov 0x200ab6(%rip),%edx # 0x60104c <bar.2180> 0x0000000000400596 <+40>: mov 0x200aac(%rip),%eax # 0x601048 <foo> 0x000000000040059c <+46>: mov %eax,%esi 0x000000000040059e <+48>: mov $0x40065c,%edi 0x00000000004005a3 <+53>: mov $0x0,%eax 0x00000000004005a8 <+58>: callq 0x400410 <printf@plt> 0x00000000004005ad <+63>: pop %rbp 0x00000000004005ae <+64>: retq End of assembler dump.

aquí está el resultado objdump

Disassembly of section .data: 0000000000601030 <__data_start>: ... 0000000000601038 <__dso_handle>: ... 0000000000601040 <foo>: 601040: 01 00 add %eax,(%rax) ... 0000000000601044 <bar.2180>: 601044: 02 00 add (%rax),%al ... 0000000000601048 <foo>: 601048: 0a 00 or (%rax),%al ... 000000000060104c <bar.2180>: 60104c: 14 00 adc $0x0,%al

Entonces, es decir, sus cuatro variables están ubicadas en el evento de sección de datos con el mismo nombre, pero con diferente desplazamiento.


Los datos declarados en una unidad de compilación entrarán en .BSS o en .Data de esa salida de archivos. Datos inicializados en BSS, no inicializados en DATA.

La diferencia entre los datos estáticos y globales viene en la inclusión de información de símbolos en el archivo. Los compiladores tienden a incluir la información del símbolo, pero solo marcan la información global como tal.

El enlazador respeta esta información. La información de símbolos para las variables estáticas se descarta o se destruye, de modo que las variables estáticas todavía se pueden referenciar de alguna manera (con opciones de depuración o símbolo). En ninguno de los casos, las unidades de compilación se ven afectadas ya que el enlazador resuelve primero las referencias locales.


No creo que haya una colisión. El uso de estática en el nivel de archivo (funciones externas) marca la variable como local en la unidad de compilación actual (archivo). Nunca es visible fuera del archivo actual, por lo que nunca debe tener un nombre.

El uso de estática dentro de una función es diferente: la variable solo es visible para la función, solo se conserva su valor en llamadas a esa función.

En efecto, la estática hace dos cosas diferentes dependiendo de dónde se encuentre. En otros casos, sin embargo, limita la visibilidad de la variable para evitar conflictos entre espacios de nombres,

Una vez dicho esto, creo que se almacenará en DATA, que tiende a tener una variable inicializada. El BSS originalmente significaba byte-set- <algo> que contenía variables que no se habían inicializado.


Si la variable estática se inicializó, se almacenaría en la memoria del segmento de datos. Si la variable estática no está inicializada (de cualquier forma que tome cero de manera predeterminada), entonces almacena en BSS (bloque iniciado por el símbolo), que es la memoria del segmento de datos sin identificar.



ambos se almacenarán de forma independiente, sin embargo, si quieres dejar en claro a otros desarrolladores, es posible que quieras envolverlos en espacios de nombres.


en el área "global y estática" :)

hay varias áreas de memoria en C ++

  • montón
  • tienda gratis
  • apilar
  • global y estático
  • const

mira here para una respuesta detallada a tu pregunta


variable estática almacenada en segmento de datos o segmento de código como se mencionó anteriormente.
Puede estar seguro de que no se asignará en stack o heap.
No hay riesgo de colisión, ya que static palabra clave static define el alcance de la variable como un archivo o función, en caso de colisión existe un compilador / vinculador para advertirle.
Un buen example


ya sabes que almacena en bss (inicio de bloque por símbolo) también denominado segmento de datos no inicializados o en segmento de datos inicializados.

vamos a tomar un ejemplo simple

void main(void) { static int i; }

la variable estática anterior no se inicializa, por lo que va al segmento de datos no inicializados (bss).

void main(void) { static int i=10; }

y, por supuesto, se inicializó por 10 para que vaya al segmento de datos inicializados.


Cómo encontrarlo tú mismo con objdump -Sr

Para comprender realmente lo que está sucediendo, debe comprender la reubicación del vinculador. Si nunca has tocado eso, considera leer esta publicación primero .

Analicemos un ejemplo de ELF Linux x86-64 para verlo nosotros mismos:

#include <stdio.h> int f() { static int i = 1; i++; return i; } int main() { printf("%d/n", f()); printf("%d/n", f()); return 0; }

Compilar con:

gcc -ggdb -c main.c

Descompile el código con:

objdump -Sr main.o

  • -S descompila el código con la fuente original entremezclada
  • -r muestra información de reubicación

Dentro de la descompilación de f vemos:

static int i = 1; i++; 4: 8b 05 00 00 00 00 mov 0x0(%rip),%eax # a <f+0xa> 6: R_X86_64_PC32 .data-0x4

y el .data-0x4 dice que irá al primer byte del segmento .data .

El -0x4 está ahí porque estamos usando el direccionamiento relativo RIP, por lo tanto, el %rip en la instrucción y R_X86_64_PC32 .

Es necesario porque RIP apunta a la siguiente instrucción, que comienza en 4 bytes después de 00 00 00 00 que es lo que se reubicará. Lo he explicado con más detalle en: https://.com/a/30515926/895245

Entonces, si modificamos la fuente a i = 1 y hacemos el mismo análisis, concluimos que:

  • static int i = 0 continúa .bss
  • static int i = 1 continúa .data