Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

const value vs. #define, which kind of chip resource will be used?

Tags:

c

embedded

if I define a macro, or use static const value, in an embedded system,
which kind of memory will be used, chip flash or chip ram? Which way is better?

like image 837
user1287356 Avatar asked Nov 29 '22 03:11

user1287356


1 Answers

I believe the answer is more complex.

Edit: I apologise for using 'should' and 'might', but without a specific compiler, or debugger, I find it had to be accurate and precise. Maybe if the question can say what compiler and platform is targeted, we can be clearer?

  1. #define NAME ((type_cast)value) consumes no space until it appears in the code. The compiler may be able to deduce something using its value (compared to using a variable with an unknown run-time value), and hence might change the code generated so that it effectively consumes no space, or may even reduce the size of code. If the compiler's analysis is that the literal value will be needed at run time, then it consume code space. The literal value is known, so the compiler should be able to allocate the optimum amount of space. Depending on the processor, it should be stored in flash, but might not be in-line code, but instead in a 'literal pool', a set of local variables, typically near to the code so compact addresses mght be used. The compiler will likely make good decisions.

  2. static const type name = value; should not consume space until it is used in the code. Even when it is used in code, it might or might not consume 'space' depending on your compiler (and, I think, the C standard it is compiling) and how the code uses the value.

    If the address of the name is never taken, then the compiler does not have to store it. If the address of the value is taken (and that code is not eliminated) then the value must be in memory. Smart compilers will detect whether or not any code in the source file takes its address. Even though it might be stored, the compiler might generate better (faster or more compact code) by not using the stored value.

    The compiler might do as good a job as #define NAME though it might be worse, than #define.

    If the value had its address taken, then the compiler treats the variable as an initialised variable, which consumes space to store the constant value. The compiler doesn't really put values into RAM or flash. That depends on the linker. In gcc, there are 'attributes' which can be used to tell the linker which segment to put a variable into. By default the compiler puts initialised variables into the default data segment, and initialised const into a read-only segment. By using attributes, the programmer can put variables into any segment. Using an appropriate linker script, which usually comes with the toolchain, segments can be put in flash. Gcc uses the readonly data segment for data like literal strings.

    name should be available in a debugger, but the #define NAME will not.

  3. There is a third approach, which is to use enum's:

    enum CONSTANTS { name = 1234, height = 456 ... };

    These may be treated by the compiler like #define constants though they are not quite as flexible because they are int size (IIRC). There is no way to take the address of an enum value, so the compiler has as many options to generate good code ad a #define NAME. They will often be available in the debugger.

  4. const type name = value; may consume RAM. It must be in memory because the compiler can't know if a code in a different file uses it, or takes its address (but gcc LTO might change that) The const tells the compiler to 'warn' (or 'error) where any code tries to change the value, e,g, using an assignment operator. Normally variables held in RAM are stored in the data or bss memory segments. By default gcc puts const into a readonly segment, the segment can set using the command line option -mrodata=readonly-data-section. that segment is .rodata on ARM.

On embedded systems, all initialised global and static variables (const or not) are also held in flash, and copied to RAM when the program starts (before main() is called). All uninitialised global or static variables are set to 0 before main() is called.

The compiler might put const variables into their own memory segment (gcc does), which may allow a linker (e.g. ld) script to put them into flash, and not allocate any RAM to them (this wouldn't work on e.g. AVR ATmega which use different imstructions to load data from flash).

like image 59
gbulmer Avatar answered Dec 15 '22 03:12

gbulmer