"const" Keyword Explained
Subscribe To Our Feed | Follow Us On Twitter | Get Updates on Email
There are a few very basic things in C that are widely misunderstood by programmers of all caders. This is not because these things are very complex, but because books and teachers do not give them their due importance while teaching beginners and the misconceptions stick even years later. A few of these are like the keywords “volatile” (covered in next post) and “const”.
Look at the following piece of code:
#include <stdio.h> int main() { const int a = 1; a = 2; printf("%d\n", a); return 0; }
You’d be quick to point out (correctly) that the above code wouldn’t compile. It would fail with an error on the lines of “assignment of read-only variable a” because a is now a “constant” because of the const type qualifier attached to it. And now comes the issue. Many start assuming (or might even be explicitly taught) that the value of a cannot be changed now. Did you think so too? Well, you thought wrong. Look at the following code:
#include <stdio.h> int main() { const int a = 1; int *b = &a; *b = 2; printf("%d %d", a, *b); return 0; }
Now, this program will compile (with a warning though, which can be removed by typecasting &a to int*) and will print the output as …any guesses? Well, lets see this “output” part later below. But how did that compilation go through?
Basically, by qualifying a variable as const, you are getting a gaurantee from the compiler that the value of that memory location cannot be changed “through that name” but can still be changed by any external program or even with the same program through another name.
But the story just doesn’t stop there. Some would say that this is impossible because by when you declare something as const, the compiler will put it in read only memory. This might be true or might not be because it is not specified in the C standard and is totally implementation dependent.
Now, lets come back to the “output” part, as in what actually would be printed on the console. Well, it could be anything because the C standard states that:
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.
So, you’d be lucky if your computer doesn’t grow a tail and starts dancing drunk to the tune of a wild african native song
. So, you could see the output as “1 1” or “2 2” with the most interesting one being “1 2”. Woah, how did that happen. It’s simple actually and if you were to see such an output, just assemble the code instead of compiling and see the assembly listing. I’ll explaing the reason here with a bit of background. Basically, there are 2 important uses of const keyword in programming:
-
To stop the programmer from mistakenly overwriting some data (e.g. a utility function that just compares 2 strings doesn’t need to modify them).
-
To allow the compiler to optimize the code for performance when you know for sure that the value of a variable would not change.
So, the “weird” output you see might be an outcome of the 2nd point above. Since you are telling the compiler that the variable is “read only”, it can optimize accesses to it in many ways, 2 of which are listed below:
-
It caches the variable’s value into a register and even though the write access to a through *b actually modifies the content of memory pointed to by a, the read access while printing the value of a still gets it from the register.
-
It could even replace the variable “a” by a constant value “1” anywhere it is used in the program.
So, there we go. I hope now you fully understand the concept behind the “const” keyword. I’ll take up even more infamous “volatile” next time. Do write in with your queries.
© Safer Code | "const" Keyword Explained
|
Liked this post? Get FREE Updates Subscribe to RSS feed |
Related posts
Tags: C, compiler, const, keyword, Optimization, read only, volatile






The printf() in the second piece of code should have a ‘*b’ as third argument rather then ‘b’ to make it consistent with the explanation in the text.
@Abhir: oops..thanks for pointing that out. Fixed.
“const” is a promise, not a guarantee.
You can always renege on your promise, but what’s the point in promising if your going to do that. The point of const is that you are promising (to yourself or other consumers of your function) not to change the contents (value) of that memory. This lets you (or others) make better decisions.
Whether or not the compiler will do anything special with a const vs non-const variable is immaterial, whatever optimization it performs is unlikely to be measurable. You certainly shouldn’t use const for that reason.
Smitty wrote: [Whether or not the compiler will do anything special with a const vs non-const variable is immaterial, whatever optimization it performs is unlikely to be measurable. You certainly shouldn’t use const for that reason.]
the syntax of the programming language is the mean for a programmer to tell the compiler what to do. Style rules and conventions exist to make it easier for others (and yourself) to understand what you told the compiler to do, but keywords like const don’t get added for the convenience of the reader. ‘const’ keyword for instance is ALL about compiler optimisations. That is the ONLY reason to use it.
[This lets you (or others) make better decisions. ]
No it doesn’t, it let the COMPILER make better decisions. There is not a single ‘decision’ – that I can think of – you should have to make based on whether or not a callee use const in it’s prototype. (well to the exception of ‘deciding’ it you can yourself use const and trickle it up, but that still only serve compiler optimisations)
norbert – I, of course, bow to your immense knowledge. I guess I’ve been using const wrong sin 1979. I never obeyed the maxim about programming for correctness before programming for speed, either.
P.S., If you don’t believe me, you might prefer to argue with Herb Sutter http://gotw.ca/gotw/081.htm
Smitty wrote:
[I guess I’ve been using const wrong sin 1979.]
That is quite remarkable, especially since the C-language ‘borrowed’ the keyword ‘const’ from C++, which didn’t exist in 1979)…. and for sake of completeness, I’ve just verified that my 1979 edition of K&R made no reference to a ‘const’ keyword
[I never obeyed the maxim about programming for correctness before programming for speed, either.]
One doesn’t perclude the other. Sure you should not declare const thing that aren’t in the hope that things will go faster – but that’s a strawman, as in “You certainly shouldn’t use const for that [performance] reason.”, like someone would use ‘const’ for performance in a place where it wouldn’t also be const-correct…
I’m still wondering what kind of ‘decision’ should a user of a function declaring const arguments make based on that information.
[I guess I’ve been using const wrong sin 1979.]
Ahh, the ravages of age – OK, make that mid-1980’s
[I’m still wondering what kind of ‘decision’ should a user of a function declaring const arguments make based on that information.]
Well, how about this one.
void func(const char* buf)
{ }
You know that the contents of the character buffer won’t change as a result of calling this function, this might mean you don’t need to store away the existing buffer contents before you call the function.
@Smitty: The user cannot assume that the buffer he passed to func won’t be changed. It can easily be if the func implementer decides to (knowingly or unknowingly) take another pointer, point it to buf and then alter away the contents to his self-contentness..
Whether a compiler will optimize or not with const, depends totally on the compiler because the spec doesn’t say anything about it. For example, if you were to pick up one of the guides for TI CCS (Optimizing Compiler Users’ Guide – SPRU198) you can see in how many ways they use const to generate optimized code.
[The user cannot assume that the buffer he passed to func won’t be changed]
Well, that’s the ‘promise’ the author of the function is making by using the const modifier. Of course, he may renege on that promise, as I’ve stated before, but if he does he’s foolish. He should either not declare the parameter as const, or not throw the const away.
[It can easily be if the func implementer decides to (knowingly or unknowingly) take another pointer, point it to buf and then alter away the contents to his self-contentness..]
Well, not unknowingly – that *should* cause a compiler error. (I’m pretty sure that’s in the spec) Of course, he may explicitly cast away const, but then we revert to my statement above.
[Whether a compiler will optimize or not with const, depends totally on the compiler because the spec doesn’t say anything about it.]
Yes, that’s my understanding as well, I would never advocate using const for performance, in fact, that’s been my stance from my very first post. Norbert disagrees, and thinks const is all about compiler optimization.
[Well, not unknowingly - that *should* cause a compiler error. (I’m pretty sure that’s in the spec) Of course, he may explicitly cast away const, but then we revert to my statement above.]
Not necesseraly: look at:
int a(….)
{
struct foo* foo
char* tag;
tag = foo_look_for_tag(foo)
rc = foo_intern_tag(foo, tag);
…
}
foo_intern_tag(struct foo* foo, cosnt char* tag)
{
foo_resize_tag_array(foo, 1);
}
sorry for the post above, I flumbled and sent it too early
foo_resize_tag_array could do all kind of thing to foo, including modfying the content pointed by tag, which was return by foo_look_for_tag() and could very well be a reference to some part of a buffer under foo.
this would not raise a compiler error nor warning, and the writter of foo_intern_tag() could have very honnestly claimed that tag is const, as far as his use of it goes.
const ‘may’ use the compiler, and the compiler is much better than human to detect these gatchas. A programming trusting const is looking for trouble.
Furthermore, many time prototypes are not const correct due to legacy isssues (the code had at one point to be compiled with K&R compiler which did not support const, and nobody revisited the code to add the conditional to allow double-compile… especially since it IS a perforamce issue, and most of the code is not performance critical.
I personally tend to use const for low-level functions that I can guarantee will not have any side-effet (as illustrated above). And it is true that most of the time it has no performance impact, because most of the time the compiler can determine the cosnt status by itself (or canot rely on it). Still on the few case where it can, it is a free lunch. And I’m banking on the evolution of the compiler and the standard that will make const be more and more useful (think anti-aliasing and other effort to allow the optimizer to do its job)
the const keyword does not, even i the c++ standard, mean that this is not modifiably though that name const is mutable.
Please red the C++ faq lite. It has a long, and correct, description of const.
http://www.parashift.com/c++-faq-lite/const-correctness.html
int main() is missing a return statement, or maybe I’m just old fashioned
@Ric: oops, what a blunder
..fixed..thanks..
[...] time we explained the real meaning of const keyword, this time it’s going to be Volatile, the other sibling of this most misunderstood duo in C [...]
nice indepth knownledge
Does any one know How const objects are imlemented in compiler?