Do all pointers have the same size in C++?

While it might be tempting to conclude that all pointers are the same size because “pointers are just addresses, and addresses are just numbers of the same size”, it is not guaranteed by the standard and thus cannot be relied upon.

The C++ standard explicitly guarantees that:

  • void* has the same size as char* ([basic.compound]/5)
  • T const*, T volatile*, and T const volatile* have the same size as T*. This is because cv-qualified versions of the same type are layout-compatible, and pointers to layout-compatible types have the same value representation ([basic.compound]/3).
  • Similarly, any two enum types with the same underlying type are layout-compatible ([dcl.enum]/9), therefore pointers to such enum types have the same size.

It is not guaranteed by the standard, but it is basically always true in practice, that pointers to all class types have the same size. The reason for this is as follows: a pointer to an incomplete class type is a complete type, meaning that you are entitled to ask the compiler sizeof(T*) even when T is an incomplete class type, and if you then ask the compiler sizeof(T*) again later in the translation unit after T has been defined, the result must be the same. Furthermore, the result must also be the same in every other translation unit where T is declared, even if it is never completed in another translation unit. Therefore, the compiler must be able to determine the size of T* without knowing what’s inside T. Technically, compilers are still allowed to play some tricks, such as saying that if the class name starts with a particular prefix, then the compiler will assume that you want instances of that class to be subject to garbage collection, and make pointers to it longer than other pointers. In practice, compilers do not seem to use this freedom, and you can assume that pointers to different class types have the same size. If you rely on this assumption, you can put a static_assert in your program and say that it doesn’t support the pathological platforms where the assumption is violated.

Also, in practice, it will generally be the case that

  • any two function pointer types have the same size,
  • any two pointer to data member types will have the same size, and
  • any two pointer to function member types will have the same size.

The reason for this is that you can always reinterpret_cast from one function pointer type to another and then back to the original type without losing information, and so on for the other two categories listed above (expr.reinterpret.cast). While a compiler is allowed to make them different sizes by giving them different amounts of padding, there is no practical reason to do this.

(However, MSVC has a mode where pointers to members do not necessarily have the same size. It is not due to different amounts of padding, but simply violates the standard. So if you rely on this in your code, you should probably put a static_assert.)

If you have a segmented architecture with near and far pointers, you should not expect them to have the same size. This is an exception to the rules above about certain pairs of pointer types generally having the same size.

Leave a Comment