Question about Constants

Hello,

To make my sketches more readable, I usually declare constants (even if they are the same value) with different names. For example for a simple error code and sensor reset reason indication:

const uint8_t ERROR_SD = 0;
const uint8_t ERROR_RTC = 1;
const uint8_t ERROR_OSF = 2;
const uint8_t ERROR_HUGO = 3;
const uint8_t ERROR_GPRS = 4;
const uint8_t ERROR_FTP = 5;
const uint8_t ERROR_DSIZE = 6;

const uint8_t REASON_REGULAR_RESET = 0;
const uint8_t REASON_SHORT_TIMEOUT = 1;
const uint8_t REASON_LIMIT_REACHED = 2;
const uint8_t REASON_INVALID_REPORT = 3;
const uint8_t REASON_INVALID_OBJECT = 4;
const uint8_t REASON_ONE_DAY_TIMEOUT = 5;
const uint8_t REASON_BOUNCING_REPORT = 6;

I'm not really familiar with the low level stuff, but I'm curious how these constants are stored. They will be stored in flash and loaded to register(s) from there, if needed? Constants with the same value will be stored only once?

Thanks in advance.

Only the values are stored. The exact storage method depends on the machine architecture and the compiler. Optimization such as re-use of identical values is compiler dependent. 8 bit constants (on a machine with an 8 bit data bus) are often embedded in the machine code, inline, using "immediate" addressing modes. Sometimes called "literal".

Constants that are too big to fit in a machine instruction are allocated a place in memory and referenced with a memory address. Whether that is in ROM or RAM is machine dependent.

By the way, the examples you show, would suit an 'enum' better than individual declarations.
https://en.cppreference.com/w/cpp/language/enum

1 Like

there no need for the compiler to allocate storage for Constants; it simply replaces the symbols in the code with the value

you can also use enum which sequentially assigns value but will assign specific values using an "=". i believe they are type int

enum    {
    ERROR_SD,
    ERROR_RTC,
    ERROR_OSF,
    ERROR_HUGO,
    ERROR_GPRS,
    ERROR_FTP,
    ERROR_DSIZE
};

enum    {
    REASON_REGULAR_RESET,
    REASON_SHORT_TIMEOUT,
    REASON_LIMIT_REACHED,
    REASON_INVALID_REPORT,
    REASON_INVALID_OBJECT,
    REASON_ONE_DAY_TIMEOUT,
    REASON_BOUNCING_REPORT
};

Thanks for the answers.

Is there any particular advantage of using the "enum method"?

Is it not self-evident? For one thing, it prevents typos from cut and pasting lines, since it assigns values by itself.

Usually, but it is compiler dependent. Optimization is not guaranteed by the language specification. Variables declared as constant, are not the same thing as literal values in expressions.

The ability to inline code a multi word constant in order to optimize some statement, depends on how that constant is used in the statement.

Inlining single word constants is so easy that it's been done almost since the beginning of C compilers. That's because it usually has processor support. That would apply to either declared or literal values of the same word size as the processor in question.

not sure what distinction you're trying to make. obviously #define macros and inline functions are more involved that simply defining a constant

what's the difference between

#define Constant    123

and

const int Constant = 123;

in the binary?

Distinction is between what you can commonly expect, and what is actually guaranteed.

Difference would depend on how literals are handled vs. variables. Since the #define is just a text replacement, you are somewhere doing something like
x = 123
vs.
x = Constant

Which could affect how optimization is performed, since it would use different underlying mechanisms.

i don't think your adding any clarification

There can't be any clarification. That is my point. Optimization is not guaranteed or defined. A "good" optimizer will translate
x = Constant
into
x = 123
All it has done, is convert a constant into a literal value.
but you can't make a general statement about that, except that "usually" it will. If it has to perform operations that require multi words, varying contexts would dictate different manipulation of the component words. An "old school" compiler would:

  1. Allocate ROM memory for the declared constant
  2. emit a macro for operations using its multi word value

Of course, they are much better than that now. But it's not guaranteed.

At the processor level, not all machine instructions are ambivalent about whether the data is variable or constant. Thus different code must be produced depending on which elements of an expression are literals or variables (taking it as a given that literals and constants are interchangeable).

Attempting to address your point directly, regardless of whether a contant replaced by a literal or a literal is involved, the compiler must allocate storage for it, if it is not possible to code it inline in machine code. Sometimes it is, sometimes it isn't. This, for example, can not be inlined:

const char flooby[] = "hello";
...
char x = flooby[ sin(log2(random())) ];