Const before or const after?
Solution 1
why is there two correct ways of specifying
const
data and in what situation would you prefer or need one over the other if any?
Essentially, the reason that the position of const
within specifiers prior to an asterisk does not matter is that the C grammar was defined that way by Kernighan and Ritchie.
The reason they defined the grammar in this way was likely that their C compiler parsed input from left-to-right and finished processing each token as it consumed that. Consuming the *
token changes the state of the current declaration to a pointer type. Encountering const
after *
means the const
qualifier is applied to a pointer declaration; encountering it prior to the *
means the qualifier is applied to the data pointed to.
Because the semantic meaning does not change if the const
qualifier appears before or after the type specifiers, it is accepted either way.
A similar sort of case arises when declaring function pointers, where:
void * function1(void)
declares a function which returnsvoid *
,void (* function2)(void)
declares a function pointer to a function which returnsvoid
.
Again the thing to notice is that the language syntax supports a left-to-right parser.
Solution 2
The rule is:
const applies to the thing left of it. If there is nothing on the left then it applies to the thing right of it.
I prefer using const on the right of the thing to be const just because it is the "original" way const is defined.
But I think this is a very subjective point of view.
Solution 3
I prefer the second syntax. It helps me keep track of 'what' is constant by reading the type declaration from right to left:
Object * const obj; // read right-to-left: const pointer to Object
Object const * obj; // read right-to-left: pointer to const Object
Object const * const obj; // read right-to-left: const pointer to const Object
Solution 4
The order of the keywords in a declaration isn't all that fixed. There are many alternatives to "the one true order". Like this
int long const long unsigned volatile i = 0;
or should it be
volatile unsigned long long int const i = 0;
??
Solution 5
The first rule is to use whichever format your local coding standards
requires. After that: putting the const
in front leads to no end of
confusion when typedefs are involved, e.g.:
typedef int* IntPtr;
const IntPtr p1; // same as int* const p1;
If your coding standard allows typedef's of pointers, then it really should insist on putting the const after the type. In every case but when applied to the type, const must follow what it applies to, so coherence also argues in favor of the const after. But local coding guidelines trump all of these; the difference isn't normally important enough to go back and change all of the existing code.
Related videos on Youtube
AJG85
Software Engineering primarily with C++ is my day job. Fields of experience in this realm are 3d graphics, embedded systems, telecom, GPS, web, multimedia, server/client architecture, multi-threading, OOP, and design patterns. Audio Engineering primarily with drums is my night job. Fields of experience in this realm are recording, mixing, sampling, mastering, live performances, and drum lessons. Everything else falls somewhere between hobby and habit.
Updated on January 29, 2022Comments
-
AJG85 over 2 years
To start you probably know that
const
can be used to make either an object's data or a pointer not modifiable or both.const Object* obj; // can't change data Object* const obj; // can't change pointer const Object* const obj; // can't change data or pointer
However you can also use the syntax:
Object const *obj; // same as const Object* obj;
The only thing that seems to matter is which side of the asterisk you put the
const
keyword. Personally I prefer to putconst
on the left of the type to specify it's data is not modifiable as I find it reads better in my left-to-right mindset but which syntax came first?More importantly why is there two correct ways of specifying
const
data and in what situation would you prefer or need one over the other if any?Edit:
So it sounds like this was an arbitrary decision when the standard for how compilers should interpret things was drafted long before I was born. Since
const
is applied to what is to the left of the keyword (by default?) I guess they figured there was no harm in adding "shortcuts" to apply keywords and type qualifiers in other ways at least until such a time as the declaration changes by parsing a * or & ...This was the case in C as well then I'm assuming?
-
jotik almost 9 yearsIn macros always add
const
after the type, e.g.#define MAKE_CONST(T) T const
instead of#define MAKE_CONST(T) const T
so thatMAKE_CONST(int *)
will correctly expand toint * const
instead ofconst int *
. -
Tom Anderson over 6 yearsI have seen these two styles referred to as "east const" and "west const".
-
YSC over 5 years@TomAnderson but really it should be "east const" and "const west".
-
-
Collin Dauphinee about 13 yearsI prefer putting it on the left, but I think putting it on the right makes more sense. You generally read types in C++ from right-to-left, for example
Object const *
is a pointer to a const Object. If you put theconst
on the left, it would read as a pointer to an Object that is const, which doesn't really flow very well. -
Heath Hunnicutt about 13 yearsThere is no such "rule." Have you got any reference to something which claims there is such a "rule"?
-
geekosaur about 13 yearsI'm under the impression that on the left is for human-style consistency with other kinds of C declarations (computer-wise it's not correct as
const
isn't a storage class, but people aren't parsers). -
AJG85 about 13 years@Heath I believe that is more of a guideline than a rule and I've heard it often as a way of remembering how the compiler will interpret it ... I understand how it works so I was only curious about the thought process behind the decision to support it both ways.
-
AJG85 about 13 yearsI think that may highlight the reason why we don't have typedefs of pointers in our rather loosely defined standards at this shop.
-
Xeo about 13 years+1 for a totally confusing definition of a simple variable. :)
-
James Kanze about 13 yearsMy policy (when I get to decide alone) is to put the const after (for the sake of coherence) and to not use typedefs to pointers (or typedefs much in general):-). And BTW, string::iterator vs. string::const_iterator should probably be factored into your decision as well. (Just to confuse things:-). There is no right answer.)
-
AJG85 about 13 yearsAh yes I could have included the behavior of
const std::string::const_iterator
as well for good measure ;) -
Bo Persson almost 13 years@rubenvb - Yes, unfortunately they are. The grammar just says that a
decl-specifier-seq
is a sequence ofdecl-specifier
s. There is no order given by the grammar, and the number of occurances for each keyword is limited only by some semantic rules (you can have oneconst
but twolong
:-) -
rubenvb almost 13 years@Bo: what about
unsigned
? I thoughtunsigned long
etc. were types of their own, and thatunsigned
wasn't really a specifier of its own? -
Bo Persson almost 13 years@rubenvb - Yes,
unsigned
is a type, the same asunsigned int
andint unsigned
.unsigned long
is another type, the same asunsigned long int
andint long unsigned
. See the pattern? -
rubenvb almost 13 years@Bo: I see the mess, got to have three to see a pattern
;)
. OK, thanks -
Tom Zych over 12 yearsKernighan co-authored the book but wasn't involved in the design of C, just Ritchie.
-
Pranit Kothari over 10 years@TomZych OMG, Till the time I was think both K&R wrote C, now you are saying K only write book of C not C?
-
cdunn2001 over 10 yearsExactly. A "constant pointer to a constant object" is
Object const* const
, notconst const Object*
. "const" cannot be on the left except in the special case where so many people absolutely love it. (See Heath above.) -
cdunn2001 over 10 yearsThis is a great example, and I agree with James Kanze. However, there is a use in typedeffing a pointer: When you might want to use a smart-point later.
-
Todd Lehman over 9 years@JamesKanze — Wait a minute, help me out here... I don't see the confusion in the posted example. What else could
const IntPtr p1
possibly mean other than "constant integer pointer" (i.e., "constant pointer to integer")? No one in their right mind, even without knowing howIntPtr
is defined, would think thatp1
is mutable. And for that matter, why would anyone incorrectly assume that*p1
is immutable? What's more, putting the const anywhere else (e.g.,IntPtr const p1
), doesn't change the semantics at all. -
James Kanze over 9 years@ToddLehman You might not see the confusion, but most C++ programmers do, and systematically get it wrong (no doubt helped by things like
std::vector<T>::const_iterator
, where it isn't the iterator which is const, but what it is pointing to). -
imallett over 9 years@HeathHunnicutt the rule exists, but it is just a little more complicated: c-faq.com/decl/spiral.anderson.html
-
Heath Hunnicutt over 9 years@GraphicsResearch that doesn't address the style question as to whether const should go before or after the type. And if it does, it's just advice, not a rule. The C standard is the rule, and it doesn't discriminate these two placements of keyword const.
-
imallett over 9 years@HeathHunnicutt: the spiral rule is the expanded version of the first commenter's comment "You generally read types in [C/]C++ from right-to-left". I presumed you were contradicting this. However, I think you may instead have been referring to the answer itself.
-
Mark Lakata almost 9 yearsYou used to be able to add
static
to the jumble of words, but only recently have compilers complained thatstatic
needs to come first. -
RastaJedi almost 8 yearsI personally would have thought
const IntPtr p1
meant the same asconst int *p1
(akaint const *p1
). I wouldn't have known for sure what it means and I definitely would have been confused. -
RastaJedi almost 8 years@rubenvb what he means it that
unsigned
by itself is just shorthand forunsigned int
(if that wasn't clear), the same wayshort
by itself is the same asshort int
. (Though do be careful, there is a difference in usingchar
vsunsigned/signed char
... it is not a type of its own, but it has its own meaning, because achar
could be signed or unsigned internally and it doesn't really matter which, but basically try to keep things consistent and for standard library functions, just use the plainchar
and let it use its own internal representation.) -
Vit Bernatik about 7 yearsI never could remember which one is which. Thanks to your explanation I finally have mnemotechnic to remember it. Thanks! Before
*
compiler parser does not know it is pointer thus it is const for data value. After * it is related to constant pointer. Brilliant. And finally it explains why I can doconst char
as well aschar const
. -
Maestro about 7 years...well, the "good reason" is not that much convincing, because other possible locations for the "const" would not mean the same thing.
const int& getInt();
int& const getInt();
-
Nick Westgate about 7 years@Maestro: I am suggesting
int const& getInt();
is better than the equivalentconst int& getInt();
whereasint& const getInt();
that you compare it with is redundant (references are already const) though legal and will usually give a warning. Anyway, const on a member function changes thethis
pointer in the function fromFoo* const
toFoo const* const
. -
Don Hatch almost 6 yearsThe guess as to why it was done this way seems rather weak/self-contradictory to me. That is, if I were defining a language and writing a compiler, and I wanted to keep it simple and "parse input from left-to-right and finish processing each token as it consumes it", as you say, it seems to me I would require the
const
to always come after the thing it's qualifying... exactly so I could always finish processing the const immediately after I consume it. So this seems to be an argument for prohibiting west-const, rather than allowing it. -
Don Hatch almost 6 years"Because the semantic meaning does not change if the const qualifier appears before or after the type specifiers, it is accepted either way." Isn't that circular reasoning? The question is why the semantic meaning is defined like that, so I don't think this sentence contributes anything.
-
Tien Do over 5 yearsEven reading from right-to-left makes more sense and it's likely the "original" way, the C++ Core Guidelines flagged "const after" is bad :) isocpp.github.io/CppCoreGuidelines/…
-
interestedparty333 over 5 years@donhatch You have to remember that, relative to today and the assumptions we make based on our familiarity with good programming language design, languages were pretty new things back then. Also, whether one has a permissive or restricted language is a value judgement. E.g., should python have a
++
operator? "The sentence", imho, helped me realize there wasn't any particular reason other than because they could. Maybe they'd make a different choice today/maybe not. -
Davis Herring almost 5 years
const
on a member function doesn’t mean at all the same thing—or isvoid set(int)&;
some sort of a reference to a function? -
Davis Herring almost 5 yearsWhile it’s a helpful memory aid, it’s a bit misleading to say that in
int *const p;
theconst
applies to the*
rather than the thing on its right,p
, which is of course what’s const-qualified in that case. -
mtraceur almost 5 years@donhatch Simpler to have one less conditional. It takes less logic and less state to just set a boolean flag upon parsing
const
without checking if it came before or after. -
Don Hatch almost 5 years@HeathHunnicutt The "rule" stated here is clearly intended to be a description of what const means... as such, it's correct, right? It sounds like maybe you misread it as being intended to be a style recommendation / advice / mandate.
-
Spock77 almost 3 years"C grammar was defined that way by Kernighan and Ritchie" - note that original C did not have 'const'