• AVR Freaks

AnsweredHot!__attribute__((persistent)), only compiles when static

Author
luk
New Member
  • Total Posts : 21
  • Reward points : 0
  • Joined: 2015/10/08 07:12:34
  • Location: 0
  • Status: offline
2019/11/13 07:54:59 (permalink)
0

__attribute__((persistent)), only compiles when static

Hello,
 
I declare (and define) a persistent structure in a header file that "feeds" multiple C files as this :

 
typedef struct{
uint8_t startChar;
uint8_t configVer;
uint32_t currentTime;
uint16_t mixingCpt;
}Config;
 
 
 
Config CONFIG __attribute__((persistent));
 

 
When compiling, I get this error:
 
build/default/production/interrupts.o: In function `Timer1_interrupt_routine':
(.pbss+0x0): multiple definition of `CONFIG'
build/default/production/main.o:(.pbss+0x0): first defined here
build/default/production/extcom.o: In function `DATA_IN_CN':
(.pbss+0x0): multiple definition of `CONFIG'

 
When I declare the structure as static
static Config CONFIG __attribute__((persistent));

it compiles well.
 
What's more, when I declare/define the structure in a C file and use it only there, it can be persistent without the being static and it compiles well.
 
What is the problem ? What does "__attribute__((persistent))" tell the linker about the memory placement ? Must a persistent variable be declared in the heap memory when used in many source file ? 
 
Thanks :)
#1
NKurzman
A Guy on the Net
  • Total Posts : 18060
  • Reward points : 0
  • Joined: 2008/01/16 19:33:48
  • Location: 0
  • Status: online
Re: __attribute__((persistent)), only compiles when static 2019/11/13 08:56:38 (permalink) ☄ Helpfulby luk 2019/11/13 09:39:01
+4 (4)
You shouldn’t declare variables in a C header file. The header file should have the definition for the struct and an extern for the variable.
The variable should be defined in a C file.
#2
Alpha Whisky
Super Member
  • Total Posts : 53
  • Reward points : 0
  • Joined: 2014/10/02 07:05:22
  • Location: 0
  • Status: offline
Re: __attribute__((persistent)), only compiles when static 2019/11/13 08:56:40 (permalink) ☼ Best Answerby luk 2019/11/13 09:39:52
+4 (4)
luk
Hello,
 
I declare (and define) a persistent structure in a header file that "feeds" multiple C files as this :

 
 
 
typedef struct{
uint8_t startChar;
uint8_t configVer;
uint32_t currentTime;
uint16_t mixingCpt;
}Config;
 
 
 
 
 
 
 
Config CONFIG __attribute__((persistent));
 
 
 

 
When compiling, I get this error:
 
build/default/production/interrupts.o: In function `Timer1_interrupt_routine':
(.pbss+0x0): multiple definition of `CONFIG'
build/default/production/main.o:(.pbss+0x0): first defined here
build/default/production/extcom.o: In function `DATA_IN_CN':
(.pbss+0x0): multiple definition of `CONFIG'

 
When I declare the structure as static
static Config CONFIG __attribute__((persistent));

it compiles well.
 
What's more, when I declare/define the structure in a C file and use it only there, it can be persistent without the being static and it compiles well.
 
What is the problem ? What does "__attribute__((persistent))" tell the linker about the memory placement ? Must a persistent variable be declared in the heap memory when used in many source file ? 
 
Thanks :)


The clue should be in the error "multiple definition of". You have defined the variable in your header file, not declared it. So each C file you include the header in gets a defined global structure called CONFIG and the linker knows you can't have multiple global objects with the same name.
 
When you changed your definition to static it will compile and link without errors because each C file you include your header in gets a structure called CONFIG with file scope. In other words you end up with a separate independent CONFIG structure in each C file. I'm betting this isn't what you wanted.
 
So, you need to do what you say you have done but didn't, you need to declare your structure in the header but only define it in one place. To declare it change "static" to "extern" and add a declaration in only one of your C files, I would suggest in main.c
 
Now, on to __attribute__((persistent). It tells the linker absolutely nothing about memory placement or use of the heap, it tells the linker not to include the structure in the linked list of memory blocks to be initialised to zero on start up. Note that it isn't magical, it will allow values to survive across a warm reset but the structure will still be full of random values after a power cycle, if you want truly persistent values then it is your responsibility to save them in non-volatile memory.
#3
Mysil
Super Member
  • Total Posts : 3488
  • Reward points : 0
  • Joined: 2012/07/01 04:19:50
  • Location: Norway
  • Status: offline
Re: __attribute__((persistent)), only compiles when static 2019/11/13 09:10:26 (permalink) ☄ Helpfulby luk 2019/11/13 09:39:41
+2 (2)
Hi,
Declaring a typedef in a header file is the right thing to do.
also declaring external variables in a header file is good.
But Defining storage allocation of variables or structures in a header file is a programming mistake as far as I know.
 
When you define storage allocation for global variables or structures in a header file,
and include this header in multiple source files,
then in principle the linker cannot know if you want the same storage several times over,
and cannot know which one to use in what context.
 
The linker may be forgiving, and if all the duplicates ask for the same properties and size,
then it may give you just one instance,
but seemingly this is not tolerated if asking for storage in the persistent section.
 
If you define the storage with static storage,
the compiler will ask for separate and private strorage for each source file.
That is fine if it is what you want.
 
If you want a common storage for all the source files using the header,
then better Declare the structure as extern  in the header file, 
and Define storage allocation in exactly One of the source files.
 
There is no problem including the header file with extern structure declaration
in the source file defining the actual storage allocation.
Compiler will check that  declaration and storage definition are consistent.
 
    Mysil
#4
luk
New Member
  • Total Posts : 21
  • Reward points : 0
  • Joined: 2015/10/08 07:12:34
  • Location: 0
  • Status: offline
Re: __attribute__((persistent)), only compiles when static 2019/11/13 11:06:50 (permalink)
0
 
Thank you very much!
 
in the header file :
extern Config CONFIG;

in the main.c file :
Config CONFIG __attribute__((persistent));

It compiles. I didn't test if it work as expected but I understand better how the declaration/definition system works.
 
extern Config CONFIG;

Config CONFIG __attribute__((persistent));

Without the extern keyword, and with a definition in main.c, the code compiles as well. Is it because a definition outside any program block is considered as a declaration only ?
Config CONFIG;
is the same as
extern Config CONFIG;
when placed outside any function ? 
 
#5
moser
Super Member
  • Total Posts : 520
  • Reward points : 0
  • Joined: 2015/06/16 02:53:47
  • Location: Germany
  • Status: offline
Re: __attribute__((persistent)), only compiles when static 2019/11/14 01:58:16 (permalink)
0
There are two things which you should look up:
-  "tentative definition" (multiple definitions in the same compile unit)
-  "external definition for the identifier of an object, [...] without the explicit use of the keyword extern" (multiple definitions across compile units)
 
The thread "multiply defined symbols" ( https://www.microchip.com/forums/FindPost/1098624 ) has some information about it and also links to other threads and resources.
#6
Jump to:
© 2019 APG vNext Commercial Version 4.5