5

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?

walmis
  • 51
  • 1
  • 3
  • Just have the linker generate a map file to see where IO::_port and IO::_pin are located. – TonyK Oct 10 '11 at 13:14
  • You probably don't have C++11 yet? Because `constexpr` would help quite a bit here. – MSalters Oct 10 '11 at 14:12
  • @walmis: what are you building here? An application? A driver? What OS? – AAT Oct 10 '11 at 14:24
  • I'm trying to build some hardware abstractions in C++, i usually do everything in C, just though I play around in C++. It's for a NXP lpc1756 cortex-m3 microcontroller. No OS, just bare hardware. – walmis Oct 10 '11 at 14:54
  • What happens if you declare them as static const? – Lundin Oct 10 '11 at 19:28

5 Answers5

2

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.

Clifford
  • 88,407
  • 13
  • 85
  • 165
1

Use a placement new to create an instance of the class in a specific memory location:

void * memPtr = 0x???????;
IO* ptrIO = new(memPtr) IO(LPC_GPIO0, 5);
John
  • 2,326
  • 1
  • 19
  • 25
  • 1
    That seems like an unnecessarily painful way to do this. Sure, it works for this trivial example, but this method doesn't scale. – Kevin Vermeer Oct 10 '11 at 14:07
1

It doesn't work with classes because you're essentially initializing the const via a function call (ctor). That's similar to const int foo = rand() at global scope: const, but not an Integral Constant Expression.

The struct code doesn't invoke any ctor, neither for the struct itself nor for any member.

MSalters
  • 173,980
  • 10
  • 155
  • 350
0

I think you will see that it does. The data section is empty which probably means that your constants were stored in the text 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.)

doron
  • 27,972
  • 12
  • 65
  • 103
  • It's strange, I tried to remove const from those members, but nothing changes, it still allocates the same amount of .text and .bss. – walmis Oct 10 '11 at 13:46
  • The constants were stored in the `text` section for sure, but at program initialization they're copied to the object's members which are held in `bss`. – Mark Ransom Oct 10 '11 at 16:13
0

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 function

Your 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.

doron
  • 27,972
  • 12
  • 65
  • 103