-1

I have this code where as usual, value of the variable "local" stays the same cause it is a const.

const int local = 10;
int *ptr = (int*)&local;
printf("Initial value of local : %d \n", local);
*ptr = 100;
printf("Modified value of local: %d \n", local);

Although, when I set local as const volatile, It changes the value of local to 100. Why is that?

const volatile int local = 10;
int *ptr = (int*)&local;
printf("Initial value of local : %d \n", local);
*ptr = 100;
printf("Modified value of local: %d \n", local);

The only meaning of volatile that I understand is that it prevents the compiler from doing optimization for that variable, just in case its value has to be changed by an outside element. But I cannot figure out how and why is volatile overriding the features of const.

EDIT- It seems from all the answers that my code was ambiguous and any output is unpredictable cause I was invoking undefined behavior.

Napstablook
  • 594
  • 1
  • 6
  • 24
  • 6
    Undefined behaviour is undefined. Any results would depend on your compiler, which you didn't specify. – HolyBlackCat Aug 29 '17 at 21:12
  • There is almost never a good reason to use `volatile` (IMHO). – Jesper Juhl Aug 29 '17 at 21:13
  • 1
    Oh, I am using c++ after almost a decade. I am practically an amateur in it. I am practicing at the moment so I am not aware of good programming practices specific to C++. Thanks for the information :) – Napstablook Aug 29 '17 at 21:15
  • 1
    if you search SO for const volatile you'll find some good examples of actual practical use, typically in embedded environments. – pvg Aug 29 '17 at 21:16
  • 1
    You declare something to be `const`. Then you subvert the type system with a cast. Then you modify it anyway. Then you expect sane results. See the problem? Your program has Undefined Behaviour - it's broken and you can't expect reasonable results. And it is *your* job to follow the rules of C++, it is *not* the compilers job to warn you about all invalid constructs. It is allowed to assume that (of course) you'd never invoke UB, so it can do whatever it likes. – Jesper Juhl Aug 29 '17 at 21:20
  • @pvg- Oh, I'll do that. Thanks :) If you'd be kind enough to point me towards a good website where I can brush up my C++ then that would be of great help. – Napstablook Aug 29 '17 at 21:20
  • @Jesper - I understand that. I was just trying to figure out the reason behind it. About how the compiler makes sense of those statements. – Napstablook Aug 29 '17 at 21:21
  • @Ramandeep as mentioned in my (updated) comment, it is not the compilers job to verify that what you did makes sense/follows rhe language rules - that is *your* job. The compiler may assume that whatever you asked it to do is valid and optimize based on that assumption or generate nonsensical code based on that assumption or do exactly what you expect based on that assumption. *You* have to make sure you follow the rules. If it's *syntactically* valid the compiler is happy (although you may not be). – Jesper Juhl Aug 29 '17 at 21:28
  • Ah, okay. It seems that using java and other languages for more than a decade has made me handicapped in that context. I get what you are saying. It would take me a bit to get used to these things. Thanks for explaining that to me. PS- Like I asked the person above, If you can point me towards a good place online, to brush up my C++, then that would be great. – Napstablook Aug 29 '17 at 21:30
  • 1
    @Ramandeep http://cppreference.com/ is always good to keep within reach. Also; https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list and https://isocpp.org/ – Jesper Juhl Aug 29 '17 at 21:39
  • 2
    @Napstablook - A C-style cast like `(int*)&local;` is telling the compiler *"I know exactly what this means, just shut up and do it"*. And the compiler does what you tell it to (jump off a cliff), even though it knows perfectly well that is doesn't work. – Bo Persson Aug 29 '17 at 22:31

2 Answers2

7

In C++, changing the value of an object that was declared const through a pointer - like what you're doing here - leads to undefined behavior, meaning that absolutely anything can happen and there are no guarantees at all about what you'll see.

In the first case, you saw the original value that was stored in the const variable, but that could just as easily have come back showing a different value. My guess is that the compiler recognized that the variable was const, cached the value, and then hardcoded it into the assembly (though I can't be sure).

In the second case, my guess is that the compiler recognized that the variable was volatile and therefore didn't cache things because it couldn't assume that something external to the program would change the value. However, you still can't assume this will work across multiple compilers or operating systems.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • The compiler would typically not generate 'assembly'. – pvg Aug 29 '17 at 21:14
  • Ah, I understand. So, We can say that this behavior had nothing to do with volatile in the first place. – Napstablook Aug 29 '17 at 21:17
  • @pvg You are correct, strictly speaking, but "assembly" is easier to say than 'generated native code.' – Solomon Slow Aug 29 '17 at 21:21
  • I don't think the compiler *could* cache a `const volatile` variable. `const volatile` effectively means "the *program* cannot change the value, but the value can still change in ways the program cannot predict." – Angew is no longer proud of SO Aug 29 '17 at 21:27
  • 1
    @Ramandeep the behaviour has nothing to do with `volatile`. It has everything to do with your program invoking UB and thus being invalid (and *any* result is acceptable). – Jesper Juhl Aug 29 '17 at 21:31
4

The compiler doesn't warn you about c-style casts:

int *ptr = (int*)&local;

this:

*ptr = 100;

is undefined behavior.

All of that doesn't have to do with volatile at all.

user0042
  • 7,917
  • 3
  • 24
  • 39
  • I understand. Let me look for some more examples to clear up how exactly volatile works. – Napstablook Aug 29 '17 at 21:18
  • @Ramandeep You'll be not able to setup an example without appropriate hardware (e.g. a FPGA bound to a certain address range) that actually changes the value independently from the compiler generated code. – user0042 Aug 29 '17 at 21:25
  • @user0042 Multithreading is easier than getting custom hardware for it. And an example which requires neither is a busywaiting loop `for (volatile int i = 0; i < 1'000'000; ++i);`. – Daniel H Aug 29 '17 at 21:38
  • 3
    @DanielH Doing that from a different thread would still have _UB_. – user0042 Aug 29 '17 at 21:40
  • In that case, I really can't seem to see any valid use of volatile. As in, in most cases, its behavior is quite .... *volatile* and unpredictable :P – Napstablook Aug 29 '17 at 21:43
  • @Ramandeep Of course there are valid uses for `const volatile`. As mentioned with dedicated HW that even becomes essentially necessary. – user0042 Aug 29 '17 at 21:46
  • @user0042 Yes, *if* the `int` was declared `const` as here. But if you have a pointer to a `const` `int`, somewhere else might legitimately have a pointer to the same `int` but non-`const`. – Daniel H Aug 29 '17 at 21:47
  • @DanielH OP was talking about a `const volatile` from the beginning. – user0042 Aug 29 '17 at 21:47
  • @Ramandeep You need `volatile` whenever something other than your code might change the results, or care about intermediate writes. You can use `const` whenever *you* don’t want to change things. Thus you can have an `int const volatile * p` for anything that you’re reading that somebody else (be it the hardware, the OS, or another thread of your own program) might change but you won’t. – Daniel H Aug 29 '17 at 21:49
  • So I understand that the takeaway from all this is, const volatile is highly hardware dependent and cannot and shouldn't be used without prior knowledge of the hardware, the program is gonna run on. – Napstablook Aug 29 '17 at 21:49
  • @user0042 Yes, but the *original* `int` doesn’t need to be declared `const` for this. See [this](https://godbolt.org/g/TjjZPS), for example, where a pointer to `const` `volatile` `int` is used for a plain non-`const` `int`, and even with `-O3` it goes to memory for the value multiple times. – Daniel H Aug 29 '17 at 21:59
  • Just to make it crystal clear: volatile is useless for multi-threaded programming. See: https://stackoverflow.com/a/4558031/87234. – GManNickG Aug 30 '17 at 03:13