Const before or const after?

79,774

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 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.

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.

Share:
79,774

Related videos on Youtube

AJG85
Author by

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, 2022

Comments

  • AJG85
    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 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?

    • jotik
      jotik almost 9 years
      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 *.
    • Tom Anderson
      Tom Anderson over 6 years
      I have seen these two styles referred to as "east const" and "west const".
    • YSC
      YSC over 5 years
      @TomAnderson but really it should be "east const" and "const west".
  • Collin Dauphinee
    Collin Dauphinee about 13 years
    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.
  • Heath Hunnicutt
    Heath Hunnicutt about 13 years
    There is no such "rule." Have you got any reference to something which claims there is such a "rule"?
  • geekosaur
    geekosaur about 13 years
    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).
  • AJG85
    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
    AJG85 about 13 years
    I think that may highlight the reason why we don't have typedefs of pointers in our rather loosely defined standards at this shop.
  • Xeo
    Xeo about 13 years
    +1 for a totally confusing definition of a simple variable. :)
  • James Kanze
    James Kanze about 13 years
    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.)
  • AJG85
    AJG85 about 13 years
    Ah yes I could have included the behavior of const std::string::const_iterator as well for good measure ;)
  • Bo Persson
    Bo Persson almost 13 years
    @rubenvb - Yes, unfortunately they are. The grammar just says that a decl-specifier-seq is a sequence of decl-specifiers. 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 :-)
  • rubenvb
    rubenvb almost 13 years
    @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?
  • Bo Persson
    Bo Persson almost 13 years
    @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?
  • rubenvb
    rubenvb almost 13 years
    @Bo: I see the mess, got to have three to see a pattern ;). OK, thanks
  • Tom Zych
    Tom Zych over 12 years
    Kernighan co-authored the book but wasn't involved in the design of C, just Ritchie.
  • Pranit Kothari
    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
    cdunn2001 over 10 years
    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
    cdunn2001 over 10 years
    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.
  • Todd Lehman
    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 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.
  • James Kanze
    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
    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
    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
    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
    Mark Lakata almost 9 years
    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.
  • RastaJedi
    RastaJedi almost 8 years
    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
    RastaJedi almost 8 years
    @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.)
  • Vit Bernatik
    Vit Bernatik about 7 years
    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.
  • Maestro
    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
    Nick Westgate about 7 years
    @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.
  • Don Hatch
    Don Hatch almost 6 years
    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
    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
    Tien Do over 5 years
    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 :) isocpp.github.io/CppCoreGuidelines/…
  • interestedparty333
    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
    Davis Herring almost 5 years
    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
    Davis Herring almost 5 years
    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.
  • mtraceur
    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
    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
    Spock77 almost 3 years
    "C grammar was defined that way by Kernighan and Ritchie" - note that original C did not have 'const'