C++ Typedef Interpretation of Const Pointers

C++ typedef interpretation of const pointers

There's no point in analyzing typedef behavior on the basis of textual replacement. Typedef-names are not macros, they are not replaced textually.

As you noted yourself

typedef CHARS const CPTR;

is the same thing as

typedef const CHARS CPTR;

This is so for the very same reason why

typedef const int CI;

has the same meaning as

typedef int const CI;

Typedef-name don't define new types (only aliases to existing ones), but they are "atomic" in a sense that any qualifiers (like const) apply at the very top level, i.e. they apply to the entire type hidden behind the typedef-name. Once you defined a typedef-name, you can't "inject" a qualifier into it so that it would modify any deeper levels of the type.

Interaction between const pointer and typedef and function declaration in c

In const int* x, const int are the specifiers and *x is the declarator. (This separation is specified by the formal grammar of C and is a reason why writing declarations as int* x misrepresents the grammar.) This declaration says that *x is a const int, meaning x is a pointer to const int.

In typedef int* int_ptr, typedef int are the specifiers, and *int_ptr is the declarator. The declaration says that *int_ptr is an int, and typedef is a special specifier that modifies it so that int_ptr is declared to be a type, rather than an object (variable).

In const int_ptr x, const int_ptr are the specifiers, and x is the declaration. So this declaration says that x is a const int_ptr.

Here const is modifying int_ptr; const int_ptr x says that x is a const pointer to an int. In const int *x, const modifies int, so it says *x is a pointer to a const int, meaning x is a pointer to a const int.

For the most part, when a function is declared with parameter type lists, the parameters must have compatible types in each declaration of the function. But there is an exception: C 2018 6.7.6.3 15 says:

… (In the determination of type compatibility and of a composite type, … each parameter declared with qualified type is taken as having the unqualified version of its declared type.)

This says that, when determining whether int add(const int_ptr x, const int_ptr y) is compatible with int add(int_ptr x, int_ptr y), the const qualifiers are ignored. Then the parameter types are the same, so the function declarations are compatible.

In int add(const int *x, const int *y), x and y are not qualified with const. They point to const int, but they themselves are not const. That is, the pointer that is x can be changed (it is not const). The fact that it points to something that is const does not make it const. So the rule about ignoring qualifiers in function parameters does not apply here; there are no qualifiers on x and y. So int add(const int *x, const int *y) and int add(int *x, int *y) do not have compatible parameter types.

The reason for this rule about ignoring qualifiers in parameter types comes from the fact that qualifiers only affect objects, not values. If we have an object x that is const, it should not be changed (through that type). But, if we have gotten the int value 3 from x and are using it in an expression, there would be no meaning to saying 3 is const. It is just a value being used in an expression; there is no memory assigned to it where we could store a new value that would change 3 to 4. Once the value of an object is retrieved from a const int, it is just an int.

Similarly, if we have a volatile int x, the volatile means the compiler must get the value of x each time it is used in an expression, because volatile means something could be changing the memory of x in ways the compiler does not know about. But, once we have gotten the value of x from memory, it is just a value. We are done with the “you have to get it from memory” part, so the volatile has no more effect.

Since function arguments are always passed by value, the qualifiers are irrelevant to the caller. When a function is declared with void foo(const int x), the const has a meaning inside the function: The compiler must issue a diagnostic if anything inside the function attempts to modify x with its const-qualified type. But the caller does not care: The caller only passes a value. When the function starts, it creates a local x for itself, and that x is const, but it has no effect on the caller. So void foo(int x) and void foo(const int x) are compatible function declarations.

typedef and containers of const pointers

Short answer:

  1. is a list of pointers to constant ints.
  2. is a list of constant pointers to ints.
  3. is the same as 2.

const (and volatile) should naturally appear after the type they qualify.
When you write it before, the compiler automatically rewrites it internally:

const int *

becomes

int const *

which is a pointer to a constant int. Lists of these will compile fine since the pointer itself is still assignable.

Pointer to constant in C

And this is one of the reasons why I strongly recommend against typedef-ing pointer types - the const semantics apply to the pointer, not to what is being pointed to.

const pduong p;

means

struct _duong * const p; // p is a const pointer to non-const type

not

const struct _duong *p;  // p is a non-const pointer to const type

In other words, you are declaring p as a const pointer to struct _duong, not as a pointer to const struct _duong.

Personally, I would recommend you ditch the typedef altogether and declare the pointer explicitly:

const struct _duong *p;

Typedefs are great for abstracting away details, and typedef-ing pointer types is fine if the user doesn't have to be aware of the "pointer-ness" of the type. In this case, the user does have to be aware of p's "pointer-ness" to use it correctly, so its type should not be hidden behind a typedef.

typedef pointer const weirdness

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.

What are the rules to typedef and pointers in c++?

Seems like already answered in :

C++ typedef interpretation of const pointers

See also Is it a good idea to typedef pointers? for more of a discussion on typedef and pointers.

C typedef const argument

This typedef

typedef float vec3[3];

defines an alias for the array type float[3]

This declaration of the parameter

vec3 const vptr

declares vptr as having array type const float[3].

Function parameters that are specified as having array types are adjusted to pointers to objects of the array element types.

So this declaration

vec3 const vptr

is adjusted to the type const float *vptr. That is it is a non constant pointer to a constant object.

This relation

vec3 const vptr <==> float* const vptr // a constant pointer to an
object

is wrong. And this statement

vptr++; // no error

confirms that.

You can not get this declaration

const float* const vptr 

using this typedef

typedef float vec3[3];


Related Topics



Leave a reply



Submit