c++ - run - why pointer size is 4 bytes in c

size of pointers and architecture (6)

It is reasonable to assume that in general sizes of pointers of any type (including pointers to functions) are equal to the target architecture bits

Depends. If you're aiming for a quick estimate of memory consumption it can be good enough.

(including pointers to functions)

But here is one important remark. Although most pointers will have the same size, function pointers may differ. It is not guaranteed that a void* will be able to hold a function pointer. At least, this is true for C. I don't know about C++.

So I was wondering what would be such circumstances if any?

It can be tons of reasons why it differs. If your programs correctness depends on this size it is NEVER ok to do such an assumption. Check it up instead. It shouldn't be hard at all.

You can use this macro to check such things at compile time in C:

#include <assert.h>
static_assert(sizeof(void*) == 4, "Pointers are assumed to be exactly 4 bytes");

When compiling, this gives an error message:

$ gcc main.c 
In file included from main.c:1:
main.c:2:1: error: static assertion failed: "Pointers are assumed to be exactly 4 bytes"
 static_assert(sizeof(void*) == 4, "Pointers are assumed to be exactly 4 bytes");

If you're using C++, you can skip #include <assert.h> because static_assert is a keyword in C++. (And you can use the keyword _Static_assert in C, but it looks ugly, so use the include and the macro instead.)

Since these two lines are so extremely easy to include in your code, there's NO excuse not to do so if your program would not work correctly with the wrong pointer size.

By conducting a basic test by running a simple C++ program on a normal desktop PC it seems plausible to suppose that sizes of pointers of any type (including pointers to functions) are equal to the target architecture bits ?

For example: in 32 bits architectures -> 4 bytes and in 64 bits architectures -> 8 bytes.

However I remember reading that, it is not like that in general!

So I was wondering what would be such circumstances?

  • For equality of size of pointers to data types compared with size of pointers to other data types
  • For equality of size of pointers to data types compared with size of pointers to functions
  • For equality of size of pointers to target architecture

It is reasonable to assume that in general sizes of pointers of any type (including pointers to functions) are equal to the target architecture bits?

If you look at all types of CPUs (including microcontrollers) currently being produced, I would say no.

Extreme counterexamples would be architectures where two different pointer sizes are used in the same program :

x86, 16-bit

In MS-DOS and 16-bit Windows, a "normal" program used both 16- and 32-bit pointers.

x86, 32-bit segmented

There were only a few, less known operating systems using this memory model.

Programs typically used both 32- and 48-bit pointers.


This modern automotive 8-bit CPU uses 16- and 24-bit pointers. Both in the same program, of course.

AVR tiny series

RAM is addressed using 8-bit pointers, Flash is addressed using 16-bit pointers.

(However, AVR tiny cannot be programmed with C++, as far as I know.)

For correctness , you cannot assume anything. You have to check and be prepared to deal with weird situations.

As a general rule of thumb, it is a reasonable default assumption .

It's not universally true though. See the X32 ABI , for example, which uses 32bit pointers on 64bit architectures to save a bit of memory and cache footprint. Same for the ILP32 ABI on AArch64.

So, for guesstimating memory use, you can use your assumption and it will often be right.

Generally pointers will be size 2 on a 16-bit system, 3 on a 24-bit system, 4 on a 32-bit system, and 8 on a 64-bit system. It depends on the ABI and C implementation. AMD has long and legacy modes, and there are differences between AMD64 and Intel64 for Assembly language programmers but these are hidden for higher level languages.

Any problems with C/C++ code is likely to be due to poor programming practices and ignoring compiler warnings. See: " 20 issues of porting C++ code to the 64-bit platform ".

See also: " Can pointers be of different sizes? " and LRiO's answer :

... you are asking about C++ and its compliant implementations, not some specific physical machine. I'd have to quote the entire standard in order to prove it , but the simple fact is that it makes no guarantees on the result of sizeof(T*) for any T, and (as a corollary) no guarantees that sizeof(T1*) == sizeof(T2*) for any T1 and T2).

Note: Where is answered by JeremyP , C99 section, subsection 8:

A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.

In GCC you can avoid incorrect assumptions by using built-in functions: " Object Size Checking Built-in Functions ":

Built-in Function: size_t __builtin_object_size (const void * ptr, int type)

is a built-in construct that returns a constant number of bytes from ptr to the end of the object ptr pointer points to (if known at compile time). To determine the sizes of dynamically allocated objects the function relies on the allocation functions called to obtain the storage to be declared with the alloc_size attribute (see Common Function Attributes). __builtin_object_size never evaluates its arguments for side effects. If there are any side effects in them, it returns (size_t) -1 for type 0 or 1 and (size_t) 0 for type 2 or 3. If there are multiple objects ptr can point to and all of them are known at compile time, the returned number is the maximum of remaining byte counts in those objects if type & 2 is 0 and minimum if nonzero. If it is not possible to determine which objects ptr points to at compile time, __builtin_object_size should return (size_t) -1 for type 0 or 1 and (size_t) 0 for type 2 or 3.

It's not correct, for example DOS pointers (16 bit) can be far (seg+ofs).

However, for the usual targets (Windows, OSX, Linux, Android, iOS) then it's correct. Because they all use the flat programming model which relies on paging.

In theory, you can also have systems which uses only the lower 32 bits when in x64. An example is a Windows executable linked without LARGEADDRESSAWARE. However this is to help the programmer avoid bugs when switching to x64. The pointers are truncated to 32 bits, but they are still 64 bit.

In x64 operating systems then this assumption is always true, because the flat mode is the only valid one. Long mode in CPU forces GDT entries to be 64 bit flat.

One also mentions a x32 ABI, I believe it is based on the same paging technology, forcing all pointers to be mapped to the lower 4gb. However this must be based to the same theory as in Windows. In x64 you can only have flat mode.

In 32 bit protected mode you could have pointers up to 48 bits. (Segmented mode). You can also have callgates. But, no operating system uses that mode.

No, it is not reasonable to assume. Making this assumption can cause bugs.

The sizes of pointers (and of integer types) in C or C++ are ultimately determined by the C or C++ implementation. Normal C or C++ implementations are heavily influenced by the architectures and the operating systems they target, but they may choose the sizes of their types for reasons other than execution speed, such as goals of supporting smaller memory use, supporting code that was not written to be fully portable to any type sizes, or supporting easier use of big integers.

I have seen a compiler targeted for a 64-bit system but providing 32-bit pointers, for the purpose of building programs with smaller memory use. (It had been observed that the sizes of pointers were a considerable factor in memory consumption, due to the use of many structures with many connections and references using pointers.) Source code written with the assumption that the pointer size equalled the 64-bit register size would break.