11

I am learning C++. In my course, it is explained that it is best to place const immediately after the thing you want to make unchangeable, because this is how const works.

Many people, including for instance Bjarne Stroustrup himself, like to write const in front. But this sometimes leads to problems:

const int *foo; //modifiable pointer to a constant int. 
int const *bar; //constant pointer to a modifiable int? No! It's a modifiable pointer to a constant int. (So the same type as foo)

An example that shows this in action:

int fun(int const *mypointer)
{
    *mypointer = 5; //Won't compile, because constant int.
    mypointer = 0; // Is okay, because modifiable pointer.
}

What makes this even more confusing, is that compilers such as g++ like to rewrite int const bar to const int bar in their error messages.

Now, this behaviour is confusing me greatly. Why does const work in this way? It would seem a lot easier to understand if it would 'just' work on the thing put after it.

Qqwy
  • 5,214
  • 5
  • 42
  • 83
  • 14
    C's insane type specifier syntax is mostly an accident of history. – Sebastian Redl Oct 07 '16 at 08:16
  • 1
    And then C++ wanted to provide backwards compat for the most part so they stuck with it. – Hatted Rooster Oct 07 '16 at 08:18
  • 5
    _But this sometimes leads to problems_ <-- Usually, it leads to problems when you don't know how it works. – skypjack Oct 07 '16 at 08:19
  • You want `int const *` to mean "`int *`, made `const`", even though `const` separates the `int` and the `*`? How is that more logical than "pointer to `int const`"? –  Oct 07 '16 at 08:22
  • @GillBates `const` was introduced by Stroustrup ("C with classes") and later adopted by ANSI C. – molbdnilo Oct 07 '16 at 08:33
  • 1
    @molbdnilo I was actually talking about the general case of type specifier syntax, as Sebastian said. – Hatted Rooster Oct 07 '16 at 08:33
  • What I am doing usually (just because I want to avoid this confusion) is either put it at the end or beginning and never in the middle. Like `const int* foo` and `int * const foo`. This may be a personal style taste but it's clearer for me and does not lead to confusion when you "forget" which way const evaluates first. – Hayt Oct 07 '16 at 08:44
  • If you want a constant pointer to a modfiable int: `int * const foo` – Puck Oct 07 '16 at 08:45
  • The rule makes (slightly) more sense [when you need more than one `const`](http://stackoverflow.com/questions/1143262/what-is-the-difference-between-const-int-const-int-const-and-int-const/1143272#1143272) – Bo Persson Oct 07 '16 at 08:56
  • 1
    Another reason to avoid pointers whenever possible. – Aziuth Oct 07 '16 at 09:28
  • 1
    ?is front to back syntax C's is Why – user207421 Oct 07 '16 at 09:30
  • The rule is to read it from right to left. `int const*` = pointer to const int. – David G Oct 07 '16 at 09:32
  • 1
    *But this sometimes leads to problems <-- Usually, it leads to problems when you don't know how it works* <-- He was right; contra-intuitive language syntax does lead to problems, because it requires remembering more rules. – Sasha Oct 07 '16 at 09:46
  • @stenliis, why on earth did you remove the `c` tag? – Sasha Oct 07 '16 at 10:05
  • 1
    @Aziuth, I hope you're kidding. The ugly (in some parts) syntax of C has absolutely no relation to valid reasons not to use pointers. The pointers as a feature is one thing and syntax of their declaration is quite another. – Sasha Oct 07 '16 at 10:23
  • If you think that code was confusing, how about `const int const signed const const const *foo;`? – Lundin Feb 27 '17 at 11:06

2 Answers2

6

C++ follows syntax of C.

It looks weird, but in C you specify not a type of variable, but a type of expression with it:

  • int v means that v is int;
  • int *v means that *v is int, so v is pointer to int;
  • int v[] means that v[…] is int, so v is array of int;
  • int v() means that v() is int, so v is function returning int;
  • etc (you always need to read such declaration from inner).

More closely to your question, in C type specification can consist of several words: unsigned char, long int, const double (even more than two — const unsigned long long int). Number of repeated words matters (long long int in general case is different from long int), but order of words doesn't (long int is the same as int long). That's why const int *p is the same as int const *p (as well as const int i is the same as int const i).

As for int * const p, it probably doesn't obey common scheme. As there is no such expression as * const p (where p is a variable) in C, so we can't explain it with something like "expression * const p will have type int". However, think, where else can we put const keyword to specify that pointer itself is constant, not its dereferenced value? (Assuming that both const int *p and int const *p mean that a dereferenced value is constant, and we don't want to introduce additional keywords into language.) Nowhere except after *; so here it goes.

Sasha
  • 3,599
  • 1
  • 31
  • 52
1

To understand a C declaration there is a Right-Left rule that is very helpful: For example

int *

is a pointer to an integer (note that you have to read that right to left). Same thing for reference to int:

int &

Now read the type of p8 from right to left:

char * const * const p8; //  const pointer to const pointer to char

I suspect that const modifies the preceding type, just to be consistent with that rule. The fact that you can put const in the very beginning of the declaration is an exception.

Note: the example comes from this article (but I changed it slightly).

esam
  • 580
  • 3
  • 13