189

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 put const 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?

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
AJG85
  • 15,849
  • 13
  • 42
  • 50
  • 13
    In macros always add `const` **after** the type, e.g. `#define MAKE_CONST(T) T const` instead of `#define MAKE_CONST(T) const T` so that `MAKE_CONST(int *)` will correctly expand to `int * const` instead of `const int *`. – jotik Jul 28 '15 at 14:15
  • 14
    I have seen these two styles referred to as "east const" and "west const". – Tom Anderson Jan 10 '18 at 16:55
  • 34
    @TomAnderson but really it should be "east const" and "const west". – YSC Nov 30 '18 at 13:31
  • 2
    I'm going to go with mid-west const, being from Wisconstsin. – C. Tewalt Sep 30 '22 at 17:29

9 Answers9

135

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 returns void *,

  • void (* function2)(void) declares a function pointer to a function which returns void.

Again the thing to notice is that the language syntax supports a left-to-right parser.

alseether
  • 1,889
  • 2
  • 24
  • 39
Heath Hunnicutt
  • 18,667
  • 3
  • 39
  • 62
  • 10
    Kernighan co-authored the book but wasn't involved in the design of C, just Ritchie. – Tom Zych Sep 10 '11 at 00:36
  • @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? – Pranit Kothari Aug 19 '13 at 11:57
  • 18
    I 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 do `const char` as well as `char const`. – Vit Bernatik Mar 10 '17 at 17:48
  • 3
    The 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 Jul 03 '18 at 23:48
  • 3
    "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. – Don Hatch Jul 03 '18 at 23:52
  • 1
    @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. – interestedparty333 Oct 08 '18 at 15:36
  • @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. – mtraceur Aug 06 '19 at 22:51
  • "C grammar was defined that way by Kernighan and Ritchie" - note that original C did not have 'const' – Spock77 Jun 17 '21 at 07:25
95

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.

zwol
  • 135,547
  • 38
  • 252
  • 361
horstforst
  • 1,073
  • 6
  • 4
  • 22
    I 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 the `const` on the left, it would read as a pointer to an Object that is const, which doesn't really flow very well. – Collin Dauphinee Mar 31 '11 at 16:54
  • There is no such "rule." Have you got any reference to something which claims there is such a "rule"? – Heath Hunnicutt Mar 31 '11 at 16:56
  • 1
    I'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). – geekosaur Mar 31 '11 at 17:09
  • 2
    @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 Mar 31 '11 at 17:10
  • 6
    @HeathHunnicutt the rule exists, but it is just a little more complicated: http://c-faq.com/decl/spiral.anderson.html – geometrian Sep 05 '14 at 06:30
  • @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. – Heath Hunnicutt Oct 27 '14 at 23:43
  • 3
    @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. – geometrian Oct 27 '14 at 23:50
  • 1
    Even reading from right-to-left makes more sense and it's likely the "original" way, the C++ Core Guidelines flagged "const after" is bad :) http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#nl26-use-conventional-const-notation – Tien Do Sep 26 '18 at 10:01
  • 1
    While it’s a helpful memory aid, it’s a bit misleading to say that in `int *const p;` the `const` applies to the `*` rather than the thing on its right, `p`, which is of course what’s const-qualified in that case. – Davis Herring Jun 16 '19 at 18:45
  • @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. – Don Hatch Aug 07 '19 at 04:33
  • When you're dealing with something like char *** I just find it easier to have const follow what it's modifying. const char *** vs char const *** vs char * const ** vs char ** const * vs char *** const. I get that most most people started with the exception, but I'll always prefer consistency, especially since the compiler will most likely sort out any confusion. And when I started C++ the const first always caused me to get confused in more complicated scenarios. Const following cleared all that up for me. – David Bradley Oct 22 '22 at 17:54
86

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
Matt Davis
  • 45,297
  • 16
  • 93
  • 124
  • 4
    Exactly. A "constant pointer to a constant object" is `Object const* const`, not `const const Object*`. "const" cannot be on the left except in the special case where so many people absolutely love it. (See Heath above.) – cdunn2001 Jan 21 '14 at 04:26
50

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;

??

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • 35
    +1 for a totally confusing definition of a simple variable. :) – Xeo Mar 31 '11 at 17:32
  • @rubenvb - Yes, unfortunately they are. The grammar just says that a `decl-specifier-seq` is a sequence of `decl-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 one `const` but two `long` :-) – Bo Persson May 19 '11 at 13:39
  • @Bo: what about `unsigned`? I thought `unsigned long` etc. were types of their own, and that `unsigned` wasn't really a specifier of its own? – rubenvb May 19 '11 at 14:21
  • 4
    @rubenvb - Yes, `unsigned` is a type, the same as `unsigned int` and `int unsigned`. `unsigned long` is another type, the same as `unsigned long int` and `int long unsigned`. See the pattern? – Bo Persson May 19 '11 at 14:41
  • 2
    @Bo: I see the mess, got to have three to see a pattern `;)`. OK, thanks – rubenvb May 19 '11 at 14:53
  • 1
    You used to be able to add `static` to the jumble of words, but only recently have compilers complained that `static` needs to come first. – Mark Lakata Jun 05 '15 at 23:13
  • 1
    @rubenvb what he means it that `unsigned` by itself is just shorthand for `unsigned int` (if that wasn't clear), the same way `short` by itself is the same as `short int`. (Though do be careful, there is a difference in using `char` vs `unsigned/signed char`... it is not a type of its own, but it has its own meaning, because a `char` 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 _plain_ `char` and let it use its own internal representation.) – RastaJedi Aug 08 '16 at 23:01
10

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.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 1
    I think that may highlight the reason why we **don't** have typedefs of pointers in our rather loosely defined standards at this shop. – AJG85 Mar 31 '11 at 17:22
  • 2
    My 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.) – James Kanze Mar 31 '11 at 17:40
  • Ah yes I could have included the behavior of `const std::string::const_iterator` as well for good measure ;) – AJG85 Mar 31 '11 at 20:28
  • This 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. – cdunn2001 Jan 21 '14 at 04:29
  • 3
    @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 how `IntPtr` is defined, would think that `p1` 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. – Todd Lehman Aug 11 '14 at 01:42
  • 3
    @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::const_iterator`, where it isn't the iterator which is const, but what it is pointing to). – James Kanze Aug 11 '14 at 09:07
  • I personally would have thought `const IntPtr p1` meant the same as `const int *p1` (aka `int const *p1`). I wouldn't have known for sure what it means and I definitely would have been confused. – RastaJedi Aug 08 '16 at 22:56
9

There are historical reasons that either left or right is acceptable. Stroustrup had added const to C++ by 1983, but it didn't make it to C until C89/C90.

In C++ there's a good reason to always use const on the right. You'll be consistent everywhere because const member functions must be declared this way:

int getInt() const;
Nick Westgate
  • 3,088
  • 2
  • 34
  • 41
  • 1
    ...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();` – Maestro Apr 28 '17 at 14:37
  • 1
    @Maestro: I am suggesting `int const& getInt();` is better than the equivalent `const int& getInt();` whereas `int& 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 the `this` pointer in the function from `Foo* const` to `Foo const* const`. – Nick Westgate Apr 29 '17 at 03:29
  • `const` on a member function doesn’t mean at all the same thing—or is `void set(int)&;` some sort of a reference to a function? – Davis Herring Jun 16 '19 at 18:41
9

C uses a right-to-left syntax. Just read the declarations from right to left:

int var = 0;

// one is a pointer to a const int
int const * one = &var; 
// two is a pointer to an int const (same as "const int")
const int * two = &var; 

// three is a constant pointer to an int
int * const three = &var;

The first thing left to the "const" is affected by it.

For more fun read this guide: http://cseweb.ucsd.edu/~ricko/rt_lt.rule.html

MacMark
  • 6,239
  • 2
  • 36
  • 41
2

When I work with the existing code, I follow the way already being used which is most of the time, const on left e.g const int a = 10; but if I got a chance to work from start I choose the "right way", means const on right e.g int const a = 10;, which is a more universal approach and straightforward to read.

As mentioned already, 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.

Here is the example code for basic use cases.

int main() {
  int const a = 10; // Constant integer
  const int b = 20; // Constant integer (same as above)

  int c = 30; // Integer (changeable)
  int * const d = &c; // Constant pointer to changeable integer

  int const * e = &a; // Changeable pointer to constant integer

  int const * const f = &a; // Constant pointer to constant integer

  return 0;
}

At the end of the day, if there is no guideline to follow, this is subjective, and harmless to use either approach.

Sajjad Ahmad
  • 421
  • 6
  • 13
1

With

using P_Int = int *;

P_Int const a = nullptr;
int * const b = nullptr;

const P_Int c = nullptr;
const int * d = nullptr;

the variables a and b are the same type as each other but, somewhat confusingly, the variables c and d are not the same type as each other. My preference is for the first scenario, without the confusion: have const on the right of the type. N.B. it is the pointer that is const with a, b, and c; but the int is const with d.

Lee
  • 11
  • 2