typedef pointer const weirdness

please consider the following code:

typedef struct Person* PersonRef;
struct Person {
  int age;
};

const PersonRef person = NULL;

void changePerson(PersonRef newPerson) {
  person = newPerson;
}

For some reason, the compiler is complaining about read-only value not assignable. But the const keyword should not make the pointer const. Any ideas?


Note that

typedef int* intptr;
const intptr x;

is not the same as:

const int* x;

intptr is pointer to int. const intptr is constant pointer to int, not pointer to constant int.

so, after a typedef pointer, i can't make it const to the content anymore?

There are some ugly ways, such as gcc's typeof macro:

typedef int* intptr;
intptr dummy;
const typeof(*dummy) *x;

but, as you see, it's pointless if you know the type behind intptr.


const PersonRef person = NULL;

is

struct Person*const person= NULL;

so you are consting the pointer and not the object.


While the problem is already solved by the answers above, I do miss the reason why...

So maybe as a rule of thumb:

  1. The const always refers to it's predecessor token.
  2. In case there is no such, it's "consting" it's successor token instead.

This rule can really help you out for declaring a pointer to const pointers or something equally neat.

Anyway, with this in mind, it should get clear why

struct Person *const person = NULL;

declares a const pointer to a mutable struct.

Think about it, your typedef "groups" the struct Person with the pointer token *. So, for writing

const PersonRef person = NULL;

your compiler sees something like this (pseudo-code):

const [struct Person *]person = NULL;

As there's nothing to const's left, it deklares the token to it's right struct Person * constant.

Well I think, this is the reason why I don't like hiding pointers by typedefs, while I do like typedefs as such. What about writing

typedef struct Person { ... } Person;
const Person *person; /*< const person */
Person *const pointer; /*< const pointer to mutable person */

and it should be quite clear to compilers and humans, what you're up to.


Never hide pointers behind typedefs, it is really really bad practice and will only create bugs.

One such infamous bug is that a typedef:ed pointer type that is declared as const will be treated as a "constant pointer to non-constant data", rather than "a non-constant pointer to constant data" which is what one intuitively expects. This is what happens in your program.


Solution:

typedef struct
{
  int age;
} Person;

const Person* person = NULL; // non-constant pointer to constant Person