ventajas variable usar una son qué que locales las hay globales estaticas entre diferencia desventajas c gcc arm gnu-arm

usar - variables locales y globales ventajas y desventajas



Diferentes variables globales estáticas comparten la misma dirección de memoria (3)

Las respuestas hasta ahora han demostrado que deberían funcionar como están escritas, pero la respuesta real está solo en los comentarios, así que la publicaré como respuesta.

Lo que estás viendo es un artefacto depurador, no la situación real. En mi experiencia, esta debe ser su primera suposición de cualquier observación verdaderamente extraña dentro del depurador. Verifique la observación en el programa en ejecución real antes de continuar. Por ejemplo, una antigua declaración de debug printf.

Resumen

Tengo varios archivos fuente de C que declaran variables globales estáticas con nombres idénticos. Mi entendimiento es que la variable global estática en cada archivo debe ser visible solo dentro de ese archivo y no debe tener una vinculación externa aplicada, pero de hecho puedo ver al depurar que las variables con nombres idénticos comparten la misma dirección de memoria.

Es como si la palabra clave static se ignorara y las variables globales se trataran como extern . ¿Por qué es esto?

Código de ejemplo

foo.c:

/* Private variables -----------------------------------*/ static myEnumType myVar = VALUE_A; /* Exported functions ----------------------------------*/ void someFooFunc(void) { myVar = VALUE_B; }

bar.c:

/* Private variables -----------------------------------*/ static myEnumType myVar = VALUE_A; /* Exported functions ----------------------------------*/ void someBarFunc(void) { myVar = VALUE_C; }

baz.c:

/* Private variables -----------------------------------*/ static myEnumType myVar = VALUE_A; /* Exported functions ----------------------------------*/ void someBazFunc(void) { myVar = VALUE_D; }

Observaciones de depuración

  1. Establezca puntos de interrupción en la línea myVar = ... dentro de cada función.
  2. Llame a someFooFunc , someBarFunc y someBazFunc en ese orden desde main.
  3. Dentro de someFooFunc myVar inicialmente se establece en VALUE_A , después de pasar sobre la línea, se establece en VALUE_B .
  4. Dentro de someBarFunc myVar está, por algún motivo, inicialmente configurado en VALUE_B antes de pasar por encima de la línea, no VALUE_A como esperaría, lo que indica que el vinculador puede haber fusionado las variables globales separadas basándose en que tienen un nombre idéntico.
  5. Lo mismo ocurre con someBazFunc cuando se llama.
  6. Si uso el depurador para evaluar el valor de &myVar cuando en cada punto de interrupción se da la misma dirección.

Herramientas y banderas

Cadena de herramientas: GNU ARM GCC (6.2 2016q4)

Opciones del compilador:

arm-none-eabi-gcc -mcpu=cortex-m4 -mthumb -mlong-calls -O1 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-move-loop-invariants -Wall -Wextra -g3 -DDEBUG -DTRACE -DOS_USE_TRACE_ITM -DSTM32L476xx -I"../include" -I"../system/include" -I"../system/include/cmsis" -I"../system/include/stm32l4xx" -I"../system/include/cmsis/device" -I"../foo/inc" -std=gnu11 -MMD -MP -MF"foo/src/foo.d" -MT"foo/src/foo.o" -c -o "foo/src/foo.o" "../foo/src/foo.c"

Opciones de enlazador:

arm-none-eabi-g++ -mcpu=cortex-m4 -mthumb -mlong-calls -O1 -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-move-loop-invariants -Wall -Wextra -g3 -T mem.ld -T libs.ld -T sections.ld -nostartfiles -Xlinker --gc-sections -L"../ldscripts" -Wl,-Map,"myProj.map" --specs=nano.specs -o ...


así hace feliz al enlazador

.globl _start _start: b _start

one.c

static unsigned int hello = 4; static unsigned int one = 5; void fun1 ( void ) { hello=5; one=6; }

dos.c

static unsigned int hello = 4; static unsigned int two = 5; void fun2 ( void ) { hello=5; two=6; }

tres.c

static unsigned int hello = 4; static unsigned int three = 5; void fun3 ( void ) { hello=5; three=6; }

En primer lugar, si optimiza, este es un código completamente muerto y no debe esperar ver ninguna de estas variables. Las funciones no son estáticas por lo que no desaparecen:

Disassembly of section .text: 08000000 <_start>: 8000000: eafffffe b 8000000 <_start> 08000004 <fun1>: 8000004: e12fff1e bx lr 08000008 <fun2>: 8000008: e12fff1e bx lr 0800000c <fun3>: 800000c: e12fff1e bx lr

Si no optimizas entonces

08000000 <_start>: 8000000: eafffffe b 8000000 <_start> 08000004 <fun1>: 8000004: e52db004 push {r11} ; (str r11, [sp, #-4]!) 8000008: e28db000 add r11, sp, #0 800000c: e59f3020 ldr r3, [pc, #32] ; 8000034 <fun1+0x30> 8000010: e3a02005 mov r2, #5 8000014: e5832000 str r2, [r3] 8000018: e59f3018 ldr r3, [pc, #24] ; 8000038 <fun1+0x34> 800001c: e3a02006 mov r2, #6 8000020: e5832000 str r2, [r3] 8000024: e1a00000 nop ; (mov r0, r0) 8000028: e28bd000 add sp, r11, #0 800002c: e49db004 pop {r11} ; (ldr r11, [sp], #4) 8000030: e12fff1e bx lr 8000034: 20000000 andcs r0, r0, r0 8000038: 20000004 andcs r0, r0, r4 0800003c <fun2>: 800003c: e52db004 push {r11} ; (str r11, [sp, #-4]!) 8000040: e28db000 add r11, sp, #0 8000044: e59f3020 ldr r3, [pc, #32] ; 800006c <fun2+0x30> 8000048: e3a02005 mov r2, #5 800004c: e5832000 str r2, [r3] 8000050: e59f3018 ldr r3, [pc, #24] ; 8000070 <fun2+0x34> 8000054: e3a02006 mov r2, #6 8000058: e5832000 str r2, [r3] 800005c: e1a00000 nop ; (mov r0, r0) 8000060: e28bd000 add sp, r11, #0 8000064: e49db004 pop {r11} ; (ldr r11, [sp], #4) 8000068: e12fff1e bx lr 800006c: 20000008 andcs r0, r0, r8 8000070: 2000000c andcs r0, r0, r12 08000074 <fun3>: 8000074: e52db004 push {r11} ; (str r11, [sp, #-4]!) 8000078: e28db000 add r11, sp, #0 800007c: e59f3020 ldr r3, [pc, #32] ; 80000a4 <fun3+0x30> 8000080: e3a02005 mov r2, #5 8000084: e5832000 str r2, [r3] 8000088: e59f3018 ldr r3, [pc, #24] ; 80000a8 <fun3+0x34> 800008c: e3a02006 mov r2, #6 8000090: e5832000 str r2, [r3] 8000094: e1a00000 nop ; (mov r0, r0) 8000098: e28bd000 add sp, r11, #0 800009c: e49db004 pop {r11} ; (ldr r11, [sp], #4) 80000a0: e12fff1e bx lr 80000a4: 20000010 andcs r0, r0, r0, lsl r0 80000a8: 20000014 andcs r0, r0, r4, lsl r0 Disassembly of section .data: 20000000 <hello>: 20000000: 00000004 andeq r0, r0, r4 20000004 <one>: 20000004: 00000005 andeq r0, r0, r5 20000008 <hello>: 20000008: 00000004 andeq r0, r0, r4 2000000c <two>: 2000000c: 00000005 andeq r0, r0, r5 20000010 <hello>: 20000010: 00000004 andeq r0, r0, r4

hay tres variables de saludo creadas (ya debe notar que no hay ninguna razón para iniciar el depurador; todo esto puede responderse simplemente examinando el compilador y la salida del vinculador, el depurador solo se interpone en el camino)

800000c: e59f3020 ldr r3, [pc, #32] ; 8000034 <fun1+0x30> 8000034: 20000000 andcs r0, r0, r0 8000044: e59f3020 ldr r3, [pc, #32] ; 800006c <fun2+0x30> 800006c: 20000008 andcs r0, r0, r8 800007c: e59f3020 ldr r3, [pc, #32] ; 80000a4 <fun3+0x30> 80000a4: 20000010 andcs r0, r0, r0, lsl r0 20000000 <hello>: 20000000: 00000004 andeq r0, r0, r4 20000008 <hello>: 20000008: 00000004 andeq r0, r0, r4 20000010 <hello>: 20000010: 00000004 andeq r0, r0, r4

Cada función está accediendo a su propia versión separada del global estático. No se combinan en una global compartida.


NOTA: Entiendo que la plataforma de destino de OP es ARM, pero aún así, estoy publicando una respuesta en términos de x86. La razón es que no tengo ningún backend ARM a mano, mientras que la pregunta no se limita a una arquitectura en particular.

Aquí hay un simple banco de pruebas. Tenga en cuenta que estoy usando int lugar de enum typedef personalizado, ya que no debería importar en absoluto.

foo.c

static int myVar = 1; int someFooFunc(void) { myVar += 2; return myVar; }

bar.c

static int myVar = 1; int someBarFunc(void) { myVar += 3; return myVar; }

C Principal

#include <stdio.h> int someFooFunc(void); int someBarFunc(void); int main(int argc, char* argv[]) { printf("%d/n", someFooFunc()); printf("%d/n", someBarFunc()); return 0; }

Lo estoy compilando en x86_64 Ubuntu 14.04 con GCC 4.8.4:

$ g++ main.c foo.c bar.c $ ./a.out 3 4

Obtener dichos resultados de manera efectiva significa que myVar variables myVar en foo.c y bar.c son diferentes. Si nos fijamos en el desmontaje (por objdump -D ./a.out ):

000000000040052d <_Z11someFooFuncv>: 40052d: 55 push %rbp 40052e: 48 89 e5 mov %rsp,%rbp 400531: 8b 05 09 0b 20 00 mov 0x200b09(%rip),%eax # 601040 <_ZL5myVar> 400537: 83 c0 02 add $0x2,%eax 40053a: 89 05 00 0b 20 00 mov %eax,0x200b00(%rip) # 601040 <_ZL5myVar> 400540: 8b 05 fa 0a 20 00 mov 0x200afa(%rip),%eax # 601040 <_ZL5myVar> 400546: 5d pop %rbp 400547: c3 retq 0000000000400548 <_Z11someBarFuncv>: 400548: 55 push %rbp 400549: 48 89 e5 mov %rsp,%rbp 40054c: 8b 05 f2 0a 20 00 mov 0x200af2(%rip),%eax # 601044 <_ZL5myVar> 400552: 83 c0 03 add $0x3,%eax 400555: 89 05 e9 0a 20 00 mov %eax,0x200ae9(%rip) # 601044 <_ZL5myVar> 40055b: 8b 05 e3 0a 20 00 mov 0x200ae3(%rip),%eax # 601044 <_ZL5myVar> 400561: 5d pop %rbp 400562: c3 retq

Puede ver que las direcciones reales de las variables estáticas en diferentes módulos son de hecho diferentes: 0x601040 para foo.c y 0x601044 para bar.c Sin embargo, están asociados con un solo símbolo _ZL5myVar , que realmente _ZL5myVar lógica GDB.

Puede verificar que por medio de objdump -t ./a.out :

0000000000601040 l O .data 0000000000000004 _ZL5myVar 0000000000601044 l O .data 0000000000000004 _ZL5myVar

Una vez más, diferentes direcciones, mismos símbolos. Cómo GDB resolverá este conflicto es puramente dependiente de la implementación.

Creo firmemente que es tu caso también. Sin embargo, para estar seguro, es posible que desee probar estos pasos en su entorno.