I have this code
class IO {
public:
IO(LPC_GPIO_TypeDef* port, int pin) : _pin(pin), _port(port) {};
const int _pin;
LPC_GPIO_TypeDef* const _port;
void test() {
LPC_GPIO0->FIOSET = 0;
}
};
IO led1(LPC_GPIO0, 5);
int main() {
led1.test();
return 0;
}
When i compile it i get
text data bss dec hex filename
656 0 8 664 298 lpc17xx
I'd expect const _port and _pin variables be stored in flash since they are marked const and initialization values are known at compile time, but they are allocated in .bss section. Is there any way to make them reside in flash memory?
EDIT: I tried this:
struct IO {
LPC_GPIO_TypeDef* port;
int pin;
void test() const {
//_port->FIOSET = _pin;
LPC_GPIO0->FIOSET = 0;
}
};
const IO led1 = {LPC_GPIO0, 5};
text data bss dec hex filename
520 0 0 520 208 lpc17xx
seems to do the trick. Why doesn't it work with classes?
Use a placement new to create an instance of the class in a specific memory location:
The line
IO led1(LPC_GPIO0, 5);
does two things. It tells the compiler to allocate a read/write structure of length 8 bytes long and then call the intiailization function viz. the construcotr to initialize it to LPC_GPIO0 and 5 respectively in writable static memory. This initialization is done by the constructor which is run before calling your main functionYour second example does not involve an intialization function viz. a constructor but is a simple initialization of non-changable memory to `LPC_GPIO0 and 5 respectively and can therefore be placed directly into the text section.
Ultimately this is an optimization issue and since the constructor is inlined and trivial it could be done away with entirely. However this probably takes a degree on intelligence that your compiler does not have.
I think you will see that it does. The
data
section is empty which probably means that your constants were stored in thetext
section. The text section is read-only and may well reside in execute-in-place NOR ROM depending on how your ROM images are built and run. (The bss section does not count since this does not contain any data per-se but rather tell the loader how much extra memory is needed for 0 initialized variables.)It doesn't work with classes because you're essentially initializing the
const
via a function call (ctor). That's similar toconst int foo = rand()
at global scope:const
, but not an Integral Constant Expression.The
struct
code doesn't invoke any ctor, neither for thestruct
itself nor for any member.The parameters to the constructor are variables, you are assigning a variable to a const, which is OK in a constructor, but while a smart optimiser might spot the occurrence of the constant expressions in the static instantiation, you are probably asking a lot, since the general case requires the constructor to accept variables, and the code will be generated for the general case.
You could probably achieve what you want using a template class, and pass the port/pin as template arguments rather than constructor arguments.
It may be compiler dependent, but in my experience you have to declare a variable as static const to force it into Flash, but that will not work for what you are trying to do.