• 5
    For a value that you want to use a name for? Define doesn't consume memory/rom-space, so if it's just for a number, that would probably be better I guess?

    Especially if there are lots of values, like gpios.
  • 14
    Depends on what you want to do. Define is a text based replacement while const declares a variable with the promise that you won't write to it programmatically.

    Usually, I declare magic numbers as define and e.g. lookup tables as const. Const has also the advantage of an associated type so that you can have some type safety.

    For longer things like strings, define may occupy the memory everywhere you use it if the linker isn't smart enough to notice that.
  • 3
    @Fast-Nop I'm doing embedded stuff, and have always used define because it seems to use less memory, but I have been told that const is proper.
  • 1
    @ewpratten I can't think of a reason why it would have to use more memory
  • 4
    @ewpratten also embedded here. Things like register addresses can well be like this:

    #define ADC_BASE 0x40012000UL
    #define ADC1_CR1 (*((volatile uint32_t *)(ADC_BASE + 0x04UL)))
    #define ADC1_DR (*((volatile const uint32_t *)(ADC_BASE + 0x4CUL)))

    Loading the addresses from a const variable would cost you both the space for the actual content in the data section and the load address for the variable in code section. Also, it would be another indirection which costs time, especially when flash access has waitstates.

    Note that you can and should use both volatile and const for registers that are read-only. That prevents erroneously writing to the ADC instead of the DAC.
  • 2
    @Fast-Nop ya. Ok. So for what I need, define is way better.
  • 1
    @Fast-Nop If it's a constant that can be copied bit for bit, wouldn't a compiler inline the value for you? Also where's the extra indirection? There might be some lower level implications that I'm not familiar with 😋
  • 3
    @beegC0de Hopefully yes, so you could do something like declaring a const pointer with init value. But the compiler is not obliged to do that, especially not when compiling with -O0 for debug mode. In that case, the variable will also take up flash space, which may be an issue.

    Without inlining, the flow e.g. for ARM CPUs goes like this: load the address of the variable into a register. Then treat the register as pointer and load what the register points to into a register, which is another flash access with wait states.

    With a define, the second step isn't necessary because the first step will directly load the value instead of the address.

    The type safety is usually done with appropriate casting right in the define like in the code snippet above.
  • 3
    @beegC0de There's also another issue. If the variable isn't file static because it's in some global CPU driver header, then it won't be optimised away if you don't use it. That is, unless you use link time optimisation, which many embedded compilers don't support.

    GCC does support LTO, but unfortunately doesn't support function stack usage analysis at the same time so that its LTO is rather useless.
  • 1
    All words like #define, #if, #else, #endif, etc. are pre-processor instructions. That means they are analyzed and tested BEFORE compiling. That's why a #define doesn't use even a single bit. It's like the replace function of most text editors.
    In the other hand, const means that the value is stored in ROM memory, can't be changed in the runtime. I only find this useful for storing strings/arrays. The memory used for store the const values depends of the compiler config and the target device. Most of MCU (like Atmega328p, aka. Arduino Uno) has EEPROM and FLASH and, with the default config, it uses the last one to store the const values.
  • 1
    @Fast-Nop I see. Can't you use flags to enable specific optimizations such as inline consts alongside -O0? I guess if you want control directly in the source it's the best option to use define though. Thanks for the explanation!
  • 2
    @beegC0de I don't know whether such an optimisation option exists. Even it it does, that would mean using pragmas and fumbling around with optimisation options in the source text.

    That is generally frowned upon because it depends on the specific compiler and the specific version, and because optimisation options should be properly encapsulated in the makefile or build script.
  • 0
    private static final
  • 2
  • 2
    @const I wonder why you would say that. Haha.
  • 1
    @Fast-Nop @beegC0de

    This is what I am programming. I know it has enough ram and good enough kernel for this to not really matter (Usually). but we have to essentially do everything in a while loop, and this loop needs to take as few cpu cycles as possible.

  • 1
    @ewpratten that's a full-blown Cortex-A9, and Cortex-A usually isn't for bare metal programming, but runs Linux, right? In that case, you probably won't have real time capability anyway in userland. On the upside, you can use GCC with LTO.

    I'm wondering how memory mapped IO works here - are you working in kernel context?
  • 1
    @Fast-Nop I unfortunately have no control over the gcc flags...
Your Job Suck?
Get a Better Job
Add Comment