[RoarAudio] When to use the 'const' keyword and when to use #define

Philipp Schafft lion at lion.leolix.org
Tue Aug 30 22:12:35 CEST 2011


I often see the const keyword missused. So here is some clarification
from my side when to use it. Maybe someone may find it useful.

Firt of all, what does const do, what does #define do?

        It tells the compiler that it is allowed to mark the data read
        only the in the current scope. The allocation, storage, usage
        and aliasing rules are unchanged by this.
        If used in the declaration of some object the compliler is
        allowed to ask the rest of the toolchain (mainly the linker) to
        put this object into a read only segment. This can be ignored by
        the compiler, linker and the OS.

        This is used for simple string substitution. The constant
        defined using #define is just put litterally where the symbolic
        name appears.
        This is all done by the preprocessor. The compiler, linker and
        other parts of the toolchain do not know about this.
        No space is allocated for the defined constants.

Some implications the above stuff has:
        An object declarated with const needs space in the programm
        binary and in the RAM of the process. It needs a symbol in the
        symbol table, needs to be resolved by the linker and by the
        dynamic linker. It may need runtime code to initialize.
        As the const keyword may be ignored at diffrent levels the
        content is can not be assumed to be truly read only and is
        subject to overwrite problems such as buffer overflows.
        If they are auto variables ('local vars of a function') they are
        on the stack and CAN NOT be protected for overwrite. A simple
        overflow or pointer miscalculation will lead into overwriting.
        As they are variables the compiler can only do very few more
        optimization with them. It can not run any compile time code
        substituation (for example a 'const div = 2; b = a / div;'
        requires a full divider run, not a simple bitshift).
        On the other pow there is the #define:
        No symbol is created. no space is allocated (expect on use, see
        The value is true constant. It's hard to overwrite a literal.
        How the compiler stores the constant is up to the compiler.
        The compiler does this context sensetive.
        For example if you set some variable to such an value the
        compiler will normally generate an single machine instroduction
        which contains the value it it's opcode (mov on ix86, ldi on
        AVR, ...).
        In the above example the compiler will detect that 'devide by
        two' is the same as a single right shift and it will generate a
        ror instroduction.
        Such code is much faster and may save a lot space.
        Also if a #define-ed constant is not used it does not need any
        resources unlike using 'const' which always allocates space.
        This is important if you have a list of harly used constants
        'const' would require significant space.
        The pro of #define that the value is embedded is also it's only
        big negative point: It is embedded in the code it uses. It is
        embedded very time it is used. For integer or float constants,
        and small strings this is no problem. This is a problem on large
        objects which are used often. For example lookup tables with
        several thousends of entrys. Such arrays or other complex
        objects are also hardly subject to big optimisatzion (for
        example accessing a fixed index in a big array can be optimized,
        accessing a random index can't.). For such objects 'const'
        normally fits better.

So, what to use? The easy rule:
        Is your constant something small (fits into a single register,
        or the part used?) -> #define
        Is your object big (normally > 16, 32, ... bytes)? -> const

Another myth about const:
        As stuff declared const is a normal object and because of this
        accessable by all normal object operations it must be in a data
        segment of the resulting binary. This also means that on a
        Harvard architecture those objects can NOT be stored in the
        programm memory. The loader part of the program needs to
        allocate RAM and initializes it with the data from the program
        memory. This requires lots of resources: RAM and program memory
        (the data is duplicated) and loader code. There is no standard
        way to put data in the program memory of such systems as well as
        no standard way to operate with it. You need to look up your
        compiler's documentation about this if needed.

Thanks for reading! Hope it helped some of you :)

 (Rah of PH2)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 482 bytes
Desc: This is a digitally signed message part
URL: <http://lists.keep-cool.org/pipermail/roaraudio/attachments/20110830/31ab21ef/attachment-0001.pgp>

More information about the RoarAudio mailing list