24

I have a const variable in my embedded C program. It's defined and initialized with 0 in program code. It's placed in a special ROM area via linker script. One can change the content of the special area via special programming procedure, but it cannot be changed during main program execution.

The question is whether I have to declare the constant as volatile. If it's not marked as volatile, is the compiler allowed to replace all references to it with 0? Or is it obligated to load it at least once during program execution?

edmz
  • 8,220
  • 2
  • 26
  • 45
mrn
  • 959
  • 5
  • 15
  • 4
    Why are you telling the compiler that it is const when it is not? – Ed Heal Apr 10 '16 at 12:24
  • 7
    Make it `const volatile`, that's exactly what `volatile` is for. – n. m. could be an AI Apr 10 '16 at 12:25
  • 9
    @EdHeal `const` doesn't mean "it won't change". It means "it won't change *via this variable*". – n. m. could be an AI Apr 10 '16 at 12:27
  • @Ed Heal It is a const from the main program point of view. Special programming procedure requires special boot process without starting the main program. So any attempt to modify the variable from the main program would be a bug (it's placed in ROM area). If it's defined as const there will appear a compiler error if any attempt occurs. – mrn Apr 10 '16 at 12:28
  • 3
    If it cannot be changed during program run, you can declare it `extern const` (without `volatile`) and omit an initializer. – n. m. could be an AI Apr 10 '16 at 12:31
  • The suggestion with extern const is good (although I'm not sure if the linker will not complain if it doesn't see a definition in code). I can also omit declaration of the const variable and refer to the address via a pointer. But the question is rather about the C language, not a best solution. – mrn Apr 10 '16 at 12:38
  • `const volatile` is very rarely used; I would expect that approach to expose compiler bugs. – zwol Apr 10 '16 at 14:23
  • 2
    `const volatile` means "I won't change this value but some other thread/process might." Can the variable change by outside means while your process/thread is running, and does the code have to be aware of the current value? Then make it `volatile`. Otherwise, just `const` is fine. – fluffy Apr 10 '16 at 20:13
  • Are you looking for a portable solution or is a platform-specific one acceptable? If the latter, what's your platform? – David Schwartz Apr 11 '16 at 00:41
  • @David Schwartz I'm interested in portable solution. – mrn Apr 12 '16 at 21:08
  • @mrn Then I think you're after the impossible because the concept of loading a value from memory has no portable meaning. For example, on typical x86 machines, it can require specific instructions to invalidate cache that there exist *no* portable way to create. – David Schwartz Apr 12 '16 at 22:08

2 Answers2

28

It looks like your variable is really a constant (i.e. doesn't change during program execution) with a value unknown to the compiler. If this is the case, you can declare it like this:

extern const int variable;

(i.e. without volatile and without an initializer) and let the linker script or other tools set up the correct value.

The compiler will then be permitted to load it and potentially leave it in a register forever, but not replace it by 0 or any other value at compile time.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • This is a good advise, however I am bound to the solution with a const defined in the code and placed in ROM correclty via linker scripts. And here comes my question - do I have to use volatile or not? – mrn Apr 10 '16 at 17:18
  • 2
    If you really need to define the variable in C, then make a separate source file containing nothing but `const int variable = 0;`, compile it separately from all your other code, and link it in. – Nate Eldredge Apr 10 '16 at 17:35
  • 5
    "I am bound to the solution" I'm not sure why exactly this is called a "solution" rather than properly a "problem". but whatever it is, absent other problems, you have to use `volatile` – n. m. could be an AI Apr 10 '16 at 17:39
11

If marked as volatile the compiler is obliged to load it from memory every time it needs it value.

If not marked as volatile, the compiler may load it once from memory, store it in a register, and use this register instead of loading it again.

A not-optimizing compiler may do this - but it also may, stupidly, load it every time. (As not reloading is in fact an optimization in itself.)

Optimizing compilers may notice the const and decide it can be compiled with its real, literal value; up to a point where the original constant does not appear at all in the .data section of your program. (Or maybe it does but it never gets "read".)

Since you change the value in a linker script, the compiler cannot "know" the value got changed after compiling. In that case, use volatile: the only way to tell the compiler not to trust that the value is known when compiling.

Jongware
  • 22,200
  • 8
  • 54
  • 100
  • "Optimizing compilers may notice the const and decide it can be compiled with its real, literal value"; that's **not at all** what `const` means. –  Apr 10 '16 at 12:34
  • 2
    Without the context that answer provides, your phrasing is misleading enough to make people believe that `const` means more than "the compiler will complain if you modify the underlying object through this lvalue". Please be aware that this is one of the toughest myths about C, right up there with "C is portable assembly", "`inline` means that the compiler will definitely inline the function everywhere", and `sizeof(int) * CHAR_BIT == 32`. –  Apr 10 '16 at 12:42
  • @Rad Lexus "up to a point where the original constant does not appear at all in the .data section of your program." What do you mean by this? – mrn Apr 10 '16 at 15:13
  • @mm: compiling a quick test with `-O0 -S` (gcc), I get `movl _const_x(%rip), %ecx` (where `const_x = 19;` is a `const` value). Repeating with `-O1`, I get `movl $19, %edx` instead: the *literal* value. The `const_x` definition still appears in the output, but it is not used anymore. So apparently gcc does not do this, but it is possible another compiler may remove 'unused data'. – Jongware Apr 10 '16 at 15:31
  • .. quite annoying, clang *always* inserts the literal value in the code, even with `-O0`. Ah for the times when compilers only did what you told them to ... – Jongware Apr 10 '16 at 15:35
  • 5
    @Rhymoid: `const` *does* mean more than that. For example, C11 final draft [section 6.7.3.6](http://port70.net/~nsz/c/c11/n1570.html#6.7.3p6), "If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined." – user2357112 Apr 10 '16 at 20:24
  • @user2357112: yeah I felt OPs backdoor way of changing a `const` value was non-standard (if only because the "linking" part moves it outside the reach and purpose of any C standard). You may want to post an answer. – Jongware Apr 10 '16 at 20:29
  • 1
    @Rhymoid "that's not at all what const means" By itself it is not what `const` means, but in combination with the as-if rule, that *is* what it `const` means to an optimizing compiler. Note that @RadLexus didn't say that it would happen with certainty. – Jordan Melo Apr 11 '16 at 18:21
  • 1
    @JordanMelo Isn't the as-if rule part of the C++ semantics, and not part of the C semantics? –  Apr 11 '16 at 18:24
  • @Rhymoid I think you may be correct about that. My mistake. Though my point still stands that Rad Lexus didn't say it would happen with certainty. He stated that an optimizing compiler may perform that action. I don't see how his phrasing is misleading. – Jordan Melo Apr 11 '16 at 18:29
  • "*If marked as volatile the compiler is obliged to load it from memory every time it needs it value.*" This is a common myth. Nothing about the semantics of `volatile` prohibit the value from being cached, and if you look at the assembler output of volatile accesses on typical compilers, you will see that they just perform a normal cached read with no special effort to force a read from memory. – David Schwartz Apr 12 '16 at 22:09
  • "the compiler is obliged to load it from memory" I thought cpu core is the one who load variable from memory.. Not compiler. – electro Sep 22 '17 at 19:52