63

While reading I came across this type of declaration and the following line -

const volatile char *p=(const volatile char *) 0x30;

The value of p is changed by external conditions only

I don't get what are the external conditions . And also what is practical use of this type of declaration?

ameyCU
  • 16,489
  • 2
  • 26
  • 41

6 Answers6

60

The const says that the flow of your program isn't going to modify what is pointed to by p. Any attempt to modify the value after dereferencing the pointer will result in a compile-time error:

*p = 'A'; // will not compile

Note that this isn't a particularly strong contract; the value at location 0x30 can still be changed through an aliasing non-const pointer, other than p:

volatile char *q = 0x30;
*q = 'A'; // will compile

Another way to break this contract is by casting away the const from p:

*(volatile char *) p = 'A'; // will compile

The volatile, however, doesn't exclude any modifications which could be caused by another thread, the kernel, an asynchronous signal handler or an external device which has access to the same memory space. This way the compiler cannot make the wrong assumption that the value pointed to by p doesn't change and will load it from memory every time it is referenced:

/*
 The character at 0x30 will be read on every iteration,
 even if the compiler has proven that the program itself
 doesn't modify the value at that address.
*/
while (*p) {
    ...
}

If the compiler was to erroneously optimise such a construct, it could emit instructions which load the value only once from memory and then keep it in a register. The register is essentially an independent copy and any changes to the original location will not reflect there, and, needless to say, this can cause some very nasty bugs.

Blagovest Buyukliev
  • 42,498
  • 14
  • 94
  • 130
  • 1
    There is a possibility that value in memory and register can be different ? Will this declaration prevent it ? – ameyCU Jul 16 '15 at 14:15
  • 8
    Yes, if the compiler decides that it will keep the value in a register and the external device modifies the memory at the designated location, the changes will not reflect in the register because it is a separate storage location. `volatile` is meant to prevent this situation. – Blagovest Buyukliev Jul 16 '15 at 14:18
  • @ameyCU: Note that this is *only* necessary in special cases -- hardware drivers and signal handlers, mostly. [Even for multi-threaded programming it is of limited, if any, use](http://stackoverflow.com/questions/4557979). You don't need `volatile` in "common" programming -- here, registers are synchronized with memory by the compiler. – DevSolar Jul 18 '15 at 09:19
  • @DevSolar Well I understand it now , we wont need this type until we are not doing system level programming. – ameyCU Jul 18 '15 at 09:37
  • If the pointer is already declared as const, this implies that the content pointed to by this pointer is not modifiable, then doesn't it ensure that value won't ever change? Then what is the need for volatile here? – Sumit Trehan Jul 21 '15 at 06:29
  • @SumitTrehan The const means *p will not (is not permitted to) be assigned to & volatile says it might get changed some other way. (That would require some implementation-dependent behaviour (or a library using it).) – philipxy Jul 22 '15 at 00:25
  • Your phrase "the flow of your program isn't going to modify what is pointed to by p' is incorrect. The object *p can be modified, even in the same scope as p is declared, through another lvalue, as long as that object isn't defined const.. – philipxy Jul 22 '15 at 09:11
  • @philipxy: Casting away the `const` is possible, but it's usually not intended in most circumstances. – Blagovest Buyukliev Jul 22 '15 at 10:14
  • 1
    @ Blagovest Buyukliev: Well, that first sentence is wrong; const does not say what you says it does. (You could add "... via lvalue p" to make your first sentence correct.) Also, modifying *p in a program does not require casting away const, one could use an unrelated lvalue; one could write (char *) 0x30 = 'a'. See the comments by AlecTeal. on the question . – philipxy Jul 22 '15 at 10:56
23

Consider a read-only hardware register, of your network card for example.

It might change outside the control of the program, so the compiler is not allowed to cache its value in a register or optimize it away. Thus, volatile.

And it's read-only, so you shouldn't write to it. Thus, const.

DevSolar
  • 67,862
  • 21
  • 134
  • 209
22

First, let me quote the example from C11 standard, chapter §6.7.3, Type qualifiers

An object declared

extern const volatile int real_time_clock;

may be modifiable by hardware, but cannot be assigned to, incremented, or decremented.

Also, related footnote (134),

A volatile declaration may be used to describe an object corresponding to a memory-mapped input/output port or an object accessed by an asynchronously interrupting function. Actions on objects so declared shall not be "optimized out" by an implementation or reordered except as permitted by the rules for evaluating expressions.

That means, the value of the variable can be modified by the hardware (through the memory-mapping), but cannot be modified "programatically".

So, the advantage is twofold here,

  • The value whenever used, will be read from the memory (cache-ing not allowed), giving you the latest updated value (if updated).
  • The value, cannot be altered, (written over) intentionally or unintentionally by the program.
Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • 1
    If a variable were declared `volatile const char msg[] = "supercalifragilisticexpealidocious"; char const *const msg2 = "us";`, and one used a utility to find the address of `msg` in the generated binary and patched it, would a compiler required to both read the contents of that memory at runtime (rather than assuming it contains the indicated string), and refrain from using its storage for anything else [like the "us" literal pointed to by msg2]? – supercat Jul 16 '15 at 17:26
  • @supercat That sounds like a brand new [tag:language-lawyer] question to me. – Riking Jul 17 '15 at 00:36
  • @supercat I think compiler will assume that it contain the indicated string every time it is referenced without rexamining if it is not present on left side of assignment expression. – ameyCU Jul 17 '15 at 04:22
  • 1
    @supercat: Whether two string literals are different entities is explicitly *unspecified* by the standard to begin with. No, AFAICT `msg` and `msg2` could not be shared, because you clearly specified that `msg` may change by external influence -- which would change the non-volatile `msg2` as well if they were shared. – DevSolar Jul 17 '15 at 05:30
  • @DevSolar: `msg` is not a pointer to a string literal; it is an allocated array. If it were not `const`, there would be no question but that the compiler was required to allocate separate storage for it; likewise if `msg2` were an allocated array rather than a pointer it would need to receive storage entirely disjoint from `msg`. I'm not sure what would forbid a compiler from making a string literal point at *anything* that could be guaranteed to yield the appropriate data, however. My main question is whether a compiler would be required to evaluate things like `strlen(msg)` at runtime. – supercat Jul 17 '15 at 15:41
  • 2
    @ameyCU: If the variable were not `volatile`, a compiler could assume the contents of `msg` could not change between when the code was compiled and when code examined those contents; on some systems hardware may guarantee that `msg` can't change between when code starts execution and when code examines it. On the other hand, it may sometimes be useful to have part of the build system search the binary for a key like "supercalifraglisticexpialodicious" [or maybe a GUID] and substitute something else. The question would be whether code from GCC would be required to "see" such a change. – supercat Jul 17 '15 at 15:48
  • Naive question, but how can something be modified, but not assigned to,incremented or decremented? – Akash Jul 17 '15 at 17:28
  • @Akash _"Modified"_ by hardware, _"cannot be assigned, incremented or decremented"_ through code. – Sourav Ghosh Jul 17 '15 at 17:31
  • @supercat: "what would forbid a compiler from making a string literal point at *anything* that could be guaranteed to yield the appropriate data." -- Nothing. But `volatile` is not guaranteed anything. – DevSolar Jul 17 '15 at 17:34
  • @DevSolar: I would hope that compilers would recognize that `volatile` forbids the compilers from making any assumptions about its contents, even if `const`, and that would certainly be true of anything that qualified `volatile const extern`. Thinking about it, I would guess that since the semantics of `volatile` are Implementation-Defined, it might be possible for an implementation to specify that reads of `const volatile` storage may return data that behaves with odd caching semantics if something causes the data to be modified. It's not clear, however, how specific or non-specific... – supercat Jul 18 '15 at 19:13
  • ...implementations' documentation must/can be with regard to Implementation-Defined Behavior while still remaining standards-compliant. – supercat Jul 18 '15 at 19:14
11

We can use the article Introduction to the volatile keyword which says:

A variable should be declared volatile whenever its value could change unexpectedly. In practice, only three types of variables could change:

  • Memory-mapped peripheral registers
  • Global variables modified by an interrupt service routine
  • Global variables within a multi-threaded application

and:

Embedded systems contain real hardware, usually with sophisticated peripherals. These peripherals contain registers whose values may change asynchronously to the program flow. As a very simple example, consider an 8-bit status register at address 0x1234. It is required that you poll the status register until it becomes non-zero. The nave and incorrect implementation is as follows:

UINT1 * ptr = (UINT1 *) 0x1234;

// Wait for register to become non-zero.
while (*ptr == 0);
// Do something else.

This will almost certainly fail as soon as you turn the optimizer on, since the compiler will generate assembly language that looks something like this:

mov    ptr, #0x1234     mov    a, @ptr loop     bz    loop

The const says your program won't change the variable but as noted in the article outside sources could and volatile prevents it being optimized away.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
7

*const volatile char *p=(const volatile char ) 0x30;
What is meant by: The value of p is changed by external conditions only.

Conceptually, you can think of this type of variable as a logical viewer. Similar in concept to the peephole in a door. A peephole allows you to view what is on the other side of the door, but does not allow you to change what is on the other side (const). However, conditions on the outside of the door can change on their own volition (they are volatile). You can see what happens, but you cannot change what happens.

In an embedded system, for example, there are hardware registers designed to provide state information about events happening in the outside world. An optical encoder, for example, used to sense RPM will set a value in a register. Each rotation, it senses light from an led and modifys the value in a hardware register. This is what is meant by external conditions. On the other side of the picture, i.e. in your code (perhaps a PID control loop), you can read this information to use in providing adjustments to the loop, but you cannot change this value, nor would you want to. (const)

From the perspective of your software then, this illustrates:

enter image description here

ryyker
  • 22,849
  • 3
  • 43
  • 87
6

const doesn't make a variable constant. It just make the compiler refuse some write access. This is still possible to write in the variable (via const-casted pointers for instance).

You can see const as a protection against coding mistakes.

This declaration make sure you don't inadvertently write to p, while telling the compiler not to optimize accesses (cache, out of order execution(?),...) because an external event may write in p.

johan d
  • 2,798
  • 18
  • 26
  • 1
    This "*... because an external process may write in `p`.*" I feel this is ambiguious. As it may not mean "process" in the sense of any running program. See *Sourav Ghosh*s answer (http://stackoverflow.com/a/31456549/694576) for why. – alk Jul 16 '15 at 14:10
  • @alk you're perfectly right, thank you! I didn't know how to generalize that. I did replace 'process' by 'event'. I'm still not proud of the formulation. – johan d Jul 16 '15 at 14:56