Summary
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?
Example Code
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;
}
Debugging Observations
- Set breakpoints on the
myVar = ...
line inside each function. - Call
someFooFunc
,someBarFunc
, andsomeBazFunc
in that order from main. - Inside
someFooFunc
myVar
initially is set toVALUE_A
, after stepping over the line it is set toVALUE_B
. - Inside
someBarFunc
myVar
is for some reason initally set toVALUE_B
before stepping over the line, notVALUE_A
as I'd expect, indicating the linker may have merged the separate global variables based on them having an identical name. - The same goes for
someBazFunc
when it is called. - If I use the debugger to evaluate the value of
&myVar
when at each breakpoint the same address is given.
Tools & Flags
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 ...
someFooFunc
,someBarFunc
andsomeBazFunc
assembler codes - this might give you a hint on either these variables actually share the same address (which should not be true). – Karraharm-none-eabi-g++
for linking. – Groundworkbar.c::myVar
and the other isfoo.c::myVar
. Also, recommends using-gstabs
if available and hopefully you don't have a classfoo
with memberc
. – Mismanage