I have several C source files that all declare individual identically named static global variables. My understanding is that the static global variable in each file should be visible only within that file and should not have external linkage applied, but in fact I can see when debugging that the identically named variables share the same memory address.
It is like the static keyword is being ignored and the global variables are being treated as extern instead. Why is this?
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;
}
myVar = ... line inside each function.someFooFunc, someBarFunc, and someBazFunc in that order from main.someFooFunc myVar initially is set to VALUE_A, after stepping over the line it is set to VALUE_B.someBarFunc myVar is for some reason initally set to VALUE_B before stepping over the line, not VALUE_A as I'd expect, indicating the linker may have merged the separate global variables based on them having an identical name.someBazFunc when it is called.&myVar when at each breakpoint the same address is given.Toolchain: GNU ARM GCC (6.2 2016q4)
Compiler options:
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"
Linker options:
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 ...
                The memory allocated for static variables is only once i.e all the objects shared by same memory but when it comes to global variables memory is allocated for each and every object. Static and global variable differ in life and scope.
Global and static variables are stored in the address space of a virtual processor, in the data segment of a shared-object file.
Global variables are stored in the data section. Unlike the stack, the data region does not grow or shrink — storage space for globals persists for the entire run of the program. Finally, the heap portion of memory is the part of a program's address space associated with dynamic memory allocation.
The difference between static variables and global variables lies in their scope. A static variable only has a block scope while a global variable can be accessed from anywhere inside the program.
NOTE: I do understand that OP's target platform is ARM, but nevertheless I'm still posting an answer in terms of x86. The reason is, I have no ARM backend in handy, while the question is not limited to a particular architecture.
Here's a simple test stand. Note that I'm using int instead of custom enum typedef, since it should not matter at all.
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; }   main.c
#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; }   I'm compiling it on x86_64 Ubuntu 14.04 with GCC 4.8.4:
$ g++ main.c foo.c bar.c $ ./a.out 3 4   Obtaining such results effectively means that myVar variables in foo.c and bar.c are different. If you look at the disassembly (by 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      You can see that the actual addresses of static variables in different modules are indeed different: 0x601040 for foo.c and 0x601044 for bar.c. However, they are associated with a single symbol _ZL5myVar, which really screws up GDB logic.
You can double-check that by means of objdump -t ./a.out:
0000000000601040 l     O .data  0000000000000004              _ZL5myVar 0000000000601044 l     O .data  0000000000000004              _ZL5myVar   Yet again, different addresses, same symbols. How GDB will resolve this conflict is purely implementation-dependent.
I strongly believe that it's your case as well. However, to be double sure, you might want to try these steps in your environment.
so.s make the linker happy
.globl _start _start: b _start   one.c
static unsigned int hello = 4; static unsigned int one = 5; void fun1 ( void ) {     hello=5;     one=6; }   two.c
static unsigned int hello = 4; static unsigned int two = 5; void fun2 ( void ) {     hello=5;     two=6; }   three.c
static unsigned int hello = 4; static unsigned int three = 5; void fun3 ( void ) {     hello=5;     three=6; }   first off if you optimize then this is completely dead code and you should not expect to see any of these variables. The functions are not static so they dont disappear:
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   If you dont optimize then
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   there are three hello variables created (you should notice by now that there is no reason to start up the debugger this can all be answered by simply examining the compiler and linker output, the debugger just gets in the way)
 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   each function is accessing its own separate version of the static global. They are not combined into one shared global.
The answers thus far have demonstrated that it should work as written, but the actual answer is only in the comments so I will post it as an answer.
What you’re seeing is a debugger artifact, not the real situation. In my experience, this should be your first guess of any truely wierd observation within the debugger. Verify the observation in the actual running program before going on. E.g. an old fashioned debug printf statement.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With