Size of pointers to pointers in memory - c

Just a quick question:
on a 32 bit machine, is a pointer to a pointer (**p) going to be 4 bytes?

The logic is that pointers are merely memory addresses. The memory address of any stored entity in a machine with 32-bit addresses is almost certainly 4 bytes. Therefore the memory address of a stored pointer is 4 bytes. Therefore a pointer to a pointer is 4 bytes. None of this is promised by the ISO C standard. It's just the way that nearly all implementations turn out.

yes... it will be 4 bytes... but its not guaranteed.

Correct. Pointers usually have a fixed size. On a 32-bit machine they are usually 32 bits (= 4 bytes)

Typically yes, addresses on 32-bit machines it will be 4 bytes.
Best bet if you don't want to make assumptions is run the old sizeof(p)

Others have already mentioned that it's most certainly 32 bits or 4 8-bit bytes.
However, depending on the hardware and the compiler it may be less or more than that.
If your machine can address its memory only as 32-bit units at 32-bit boundaries, you will have to have a bigger pointer to address and access 8-bit portions (chars/bytes) of every 32-bit memory cell. If the compiler here decides not to have pointers of different sizes, all pointers (including pointers to pointers) become 34+-bit long.
Likewise, if the program is very small and can fit into 64KB, the compiler may be able to reduce all pointers to 16 bits.

Related

size of pointers in c language

What is meant by the size of a pointer? Shouldn't the size of pointer depend on the type? Most of the sources say the size of a pointer if 4 or 8 bytes. I need some clarity on this claim.
For size of a pointer I would mean the number of bits (or bytes) necessary to hold that pointer in memory, or send its value across some channel, and this is (possibly) different from the size of the object the pointer points to.
Then, it can be assumed as fairly true the affirmation that pointer sizes are commonly 32 or 64 bits (4 or 8 bytes), in the sense that the systems much talked about (computers, smartphones and tablets) have pointers of that size.
But there are other systems around, smaller like DOS-based PCs or microcontrollers for embedded systems, where a pointer can be 16 bits wide or even less, and bigger systems with bus width of, say, 128 bits.
I worked in the past with the Intel 8051 CPU, which had pointers 8 bits wide, 16 bits wide, and 24 bits wide. Of course they were not freely mixable... That CPU was indeed quite strange, having about 3-4 different (and little) areas of memory; a "specialized" pointer could point only in its special area, while the 24 bit wide one could point to any area because in the upper byte there was a "selector".
Another matter is the size of the object the pointer points to. On normal computers it is a byte, but sometimes, on certain systems, it is impossible to address bytes on odd addresses in this way, so pointer arithmetic gets complicated. The 8051 (I like it!) had even pointers pointing to bits! So the size of the pointed object was actually an eight of byte, and incrementing the pointer by one could, or could not, address a different memory location than before.
Data is stored in memory. That memory has an address. Pointers hold the memory address for where the data starts.
Specifically, pointers usually hold the address of the "first byte" of data where the type resides (note that technically, the first byte might contain the last bits of data, depending on endianness).
i.e., if a long double is 128bit (16 bytes), the pointer value will point to the first byte and the pointer type will indicate the numbers of bytes that should be read.
Should you "cast" the long double pointer in the example to an int * (an int pointer), only sizeof(int) bytes would be read - but the value, the address of the first byte, will remain the same.
Hence, the pointer value is oblivious to the size of the data, the pointer only needs to be large enough to contain the address of the first byte. For this reason, usually pointers have the same length which is derived from a computer's "address space".
It is very similar to a catalog card in a library. Just like a "book address" in a library depends on the size of the library, the pointer value (the memory address) depends on the size of the computer's "address space", not the size of the type.
On most 32 bit and 64 bit CPUs, the address space is limited to either 32 or 64 bits. However, some systems have special address spaces for special pointers (such as function pointers)... this is mostly obsolete. It was more in use when CPUS were smaller than 32 bits and the "address space" was limited.
Note that values in the address space (pointers) can point to any location on the hardware (usually a byte in memory, but sometimes a register or a piece of hardware)... this is why the OS (kernel), leveraging some hardware support, will usually expose a "virtual" address space per process, shielding the hardware and other processed from a misbehaving process.
P.S.
I loved the answer given by #linuxfansaysReinstateMonica ... However, I found that I wanted to clarify some of the information in that answer. You should really read it. This answer is mostly a clarification for their answer.

Sizeof pointer for 16 bit and 32 bit

I was just curious to know what would the sizeof pointer return for a 16 bit and a 32 bit system
printf("%d", sizeof(int16 *));
printf("%d", sizeof(int32 *));
Thank you.
Short answer: On a 32bit Intel 386 you will likely see these returning 4, while targeting a 16bit 8086 you might most likely see either 2 or 4 depending on the memory model you selected.
The details
First standard C does not mandate anything particular about pointers, only that they need to be able to "point to" the given variable, and pointer arithmetic needs to work within the data area of the given variable. Even a C interpreter which has some exotic representation of pointers is possible, and given this flexibility pointers truly might be of any size depending on what you target.
Usually however compilers indeed represent pointers by memory addresses which makes several operations undefined by the C standard "usually working". The way how the compiler chooses to represent a pointer depends on the targeted architecture: compiler writers obviously chose representations which are either or both useful and efficient.
An example to useful representations is generic pointers on a Harward architecture micro. They allow you to address both code and data ram. On a 8 bit micro they might be encoded as one type byte plus 2 address bytes, this obviously implies that whenever you dereference one such pointer, more complex code has to be emitted to load the contents from the proper place.
That gives a good example to an efficient representation: why not have specific pointers then? One which points to code memory, an other which points to data memory? Just 2 bytes (assuming 16bit address space as usual for 8bit micros such as the 8051), and no need to select by type.
But then you have multiple types of pointers, eh (again the 8051: you will likely have at least one additional type of pointer pointing within it's internal RAM too...). The programmer then needs to think about which particular pointer type he needs to use.
And of course the sizes also differ. On this hypothetical compiler targeting the 8051, you would have a generic pointer type of 3 bytes, an external data memory pointer type of 2 bytes, a code memory pointer of 2 bytes, and an internal RAM pointer type of 1 byte.
Also note that these are types of pointers, and not the types of data they point to (function pointers are a little off here as the fact a pointer is a function pointer implies that it is of a different type than data pointers while not having any specific syntax difference except that the data type it points to is a function type).
Back to your 16bit machine, assuming it is a 8086:
If you use some memory model where the compiler assumes you have a single data segment, you will likely get 2 byte data pointers if you don't specifically declare one near or far. Otherwise you will get 4 byte pointers by default. The representation of 2 byte pointers is usually simply the 16bit offset, while for 4 byte pointers it is a segment:offset pair. You can always apply a near or far specifier to explicitly make your pointers one or another type.
(How near pointers work in an program which also uses far pointers? Simply there is a default data segment generated by the compiler, and all nears are located within that. The compiler may simply permanently, or at least most of the time, have the ds segment register filled with the default data segment, so access of data pointed by nears can be faster)
The size of the a pointer depends on the architecture. Precisely, it depends on the size of the addresses used in that architecture which reflects the size of the bus system to access the memory.
For example, on 32 bits architecture the size of an address is 4 bytes :
sizeof (void *) == 4 Bytes.
On 64bits, addreses have size 8 bytes:
sizeof (void *) == 8 bytes.
Note, that all pointers have the same size interdependently of the type. So if you execute your code, the size of a int16 pointer and the size of int32 pointer will be the same.
However, the size of a pointer on a 16 bit system should be 2 bytes. Usually, 16bit systems have really few memory (some megabytes) and 2 bytes are enough to address all its locations. To be more precise, with a pointer of 16 bit the maximum memory you can have is around 65 KB. (really few compared to the amount of memory of a today computer).

When malloc returns, what does 8-byte alignment mean?

In libc's malloc(x), the function is said to return a pointer to a memory region of at least x bytes and the pointer is aligned to 8 bytes. What does this alignment mean? THank you.
It means that the pointed address mod 8 is 0:
pointer % 8 == 0
This can be important for low level operations where it may impact correctness or efficiency. See also this answer.
It means that the memory starts on an address that is a multiple of 8.
As for why you would even care: For memory that's not aligned, the CPU sometimes requires two accesses to read it all. In some cases, it won't even try and will just throw an error. The mention of "aligned to 8 bytes" is so that the caller knows whether it'll have to do any fudging of the pointer or not.
(Usually, you won't care -- the compiler takes care of most of the alignment issues for you. But the info's there in case you need it for some reason.)
Memory alignment describes the modulus of the addresses. So 8 byte alignment means that he addresses are multiples of eight.
This was critical on many older systems where addresses needed to be aligned on a 'word' boundary, often a multiple of four bytes or two bytes. If it wasn't properly aligned the program crashed with an 'alignment error'.
More recent machines fix this problem by loading from any address, but often that means that it takes few more cycles to load the data.

Size of pointers and if that size is dependent of the architecture

Well, sorry for the question, is more like a general culture one (haven't found precise answers).
If I have something like
char * Field
or
void * Field
or
double pointers
The size of the pointer is the same? (as far I remember from college it was 4 bytes but ...)
Is the size of the pointer the same depending of the architecture of the CPU?
If I point to a data structure, the size of the the pointer itself is the same, isn't it?
Assume the examples in C (I would be prone to believe that it will be the same for other languages that does not handle pointers directly)
The size of the pointer is the same? (as far I remember from college it was 4 bytes but ...)
Not necessarily the same and not necessarily 4 bytes: Are all data pointers the same size in one platform for all data types?
Is the size of the pointer the same depending of the architecture of the CPU?
It varies from archtecture to architecture. Even on the same hardware it can vary from operating system to operating system (e.g. 32-bit vs 64-bit).
If I point to a data structure, the size of the the pointer itself is the same, isn't it?
Again, not necessarily: Are all data pointers the same size in one platform for all data types?
In most systems, the size of the pointers is same, but C don't guarantee that. It's just promise you that void* is wide enough to contain every pointer type (except of pointer to function). and yes - it depends of the CPU. (In 64bit systems, pointer is usually 8 bytes)
A 32-bit system usually has pointers of size 4 bytes and a 64-bit machine, usually has pointers of 8 bytes size.
The keyword here is of course - usually, it is entirely possible that the device you maybe using is based on Harvard architecture(Or some other bus architecture scheme), which has separate memories for data and code regions.
Hence separate buses with different widths, therefore it can be a possibility that the size of variable pointers (int*, double*, long int* etc.) is 8-bit but the size of function pointer is 16-bit, in the very same architecture.
1) The size of a pointer is the same for all pointer types.
2) Generally on a 32 bit architecture it will be 4 bytes, and on a 64 bit architecture it will be 8 bytes.
3) The size of the pointer will be the same no matter what you point it to.

Is there any way the size of the pointer can be changed from 2 bytes?

Can we anyhow change the size of the pointer from 2 bytes so it can occupy more than 2 bytes?
Sure, compile for a 32 (or 64) bit platform :-)
The size of pointers is platform specific, it would be 2 bytes only on 16-bit platforms (which have not been widely used for more than a decade - nowadays all mainstream [update](desktop / laptop / server)[/update] platforms are at least 32 bits).
If your pointer size is 2 byte that means you're running on a 16-bit system.
The only way to increase the pointer size is to use a 32-bit or 64-bit system instead (which would mean any desktop or laptop computer built in the last 15 years or so).
If you're running on some embedded device that uses 16-bit, your only option would be to switch to another device which uses 32-bits (or just live with your pointers being 16-bit).
When a processor is said to be "X-bit" (where X is 16, 32, 64, etc), that X refers to the size of the memory address register. Thus a 16-bit system has a memory address register of 2 bytes.
You cannot cast a 4-byte address to anything smaller because it would lose part of where it's pointing to. (A 2-byte memory address register can only point to 2^16=64KB of memory, whereas a 4-byte register can point to 2^32=4GB of memory.)
You can always "step-up" (ie, run a 32-bit software application on a 64-bit computer) because there's no loss in pointer range. But you can never step down, which is why 64-bit programs don't run on 32-bit systems.
Think of a pointer as a number, only instead of an actual value used for computation, it's the number of a 'slot' in the memory map of the system.
A pointer must be able to represent the highest position of the memory map. That is, it must have at least the amount of bytes required to represent the number of the highest position.
In a 16-bit system, the highest possible position is 0xFFFF (a 16-bit number with all the bits set to 1). A pointer must also have 16 bits, so it can reach that number.
Generalizing, in an X-bit system, a pointer will have X bits.
You can store a pointer in a larger variable, the same way you can store the number 1 in a char, in an int, or an unsigned long long if you wanted to; but there's little point to that: think that, the same way a shorter pointer won't be able to reach the highest memory position, a longer pointer would be able to point to things that can't actually exist in memory, so why have it?
Also, you'd have to 'trick' the compiler for that. If you use the pointer notation in your code, the compiler will always use the correct amount of bytes for it. You can instruct the compiler to compile for another platform, though.

Resources