Is size of char * same as size of int *? - c

I know:
char * is a pointer to char.
and
int * is a pointer to int.
So, i want to confirm following two things:
So now suppose I am on 32 bit machine, then that means memory addresses are 32 bit wide.
Thus that means size of char * and int * is both 32 bits ( 4 bytes), right ?
Also is size of char * * also same as size of int * ?
suppose I have:
int * ptr;
Thus now doing *((char * *) ptr) = 0x154 is same as *((int *) ptr) = 0x514 same, right ?
( 0x514 is just any random memory address)
Platform: I am on x86.
P.S.: I know type casting is not a suggested way to code. But I am doing Kernel coding, thus I HAVE TO do type casting !

In C pointers are not guaranteed to have the same size. Now in reality most implementations pointers will be the same size, but that is an implementation detail of the compiler.
From the C Faq:
The old HP 3000 series uses a different addressing scheme for byte
addresses than for word addresses; like several of the machines above
it therefore uses different representations for char * and void *
pointers than for other pointers
Depending on the ``memory model'' in use, 8086-family processors (PC
compatibles) may use 16-bit data pointers and 32-bit function
pointers, or vice versa.
Also *((char *)ptr) = 0x154 is not the same as *((int *)ptr) = 0x154. Because you are dereferencing the pointer you will write data the size of a char and the size of an int into the location pointed to by ptr. Assuming an 8 bit char and a 32 bit int, *((char *)ptr) = 0x154 will write0x154 to the memory address assigned to ptr and *((int *)ptr) = 0x154 will write 0x0000000154 to the 4 bytes starting at the address assigned to ptr.

Technically speaking, the C standard only guarantees that sizeof(char) == 1, and the rest is up to the implementation. But on modern x86 architectures (e.g. Intel/AMD chips) it's fairly predictable.
You've probably heard processors described as being 16-bit, 32-bit, 64-bit, etc. This usually means that the processor uses N-bits for integers. Since pointers store memory addresses, and memory addresses are integers, this effectively tells you how many bits are going to be used for pointers. sizeof is usually measured in bytes, so code compiled for 32-bit processors will report the size of pointers to be 4 (32 bits / 8 bits per byte), and code for 64-bit processors will report the size of pointers to be 8 (64 bits / 8 bits per byte). This is where the limitation of 4GB of RAM for 32-bit processors comes from -- if each memory address corresponds to a byte, to address more memory you need integers larger than 32-bits.
In practice, pointers will be size 2 on a 16-bit system (if you can find one), 4 on a 32-bit system, and 8 on a 64-bit system, but there's nothing to be gained in relying on a given size

Related

C programming pointer, bytes and memory allocation have 8 question

I am trying to get the bytes and pointers and how they are stored can any one explain or answer some of my questions. Thank you
int num = 513; <-- allocating a 4 bit memory by initializing
//[01][02][00][00] <-- (numbers are sorted and shown as litle endian)
char * ptr = &num; //char is (one byte)
↓
//[01][02][00][00]
// pointer always start from the [0] (as in this array byte length)
// in the allocated address in the memory ptr[0] is in this case = [01]
// (printed as %x02 "printf("the byte %02x\n",ptr[0]);" - if it's only
//single number 1 a zero will be added on the length so it prints out as 01)
int * ptr = &num; //now creating a pointer with the type of int (four bytes)
↓ ↓ ↓ ↓
//[01][02][00][00]
how can i access the first byte of this int pointer? [question01]
is there a way to see the bites inside the of the first byte([01])? [question02]
where does the pointer save the address? does it have to allocate a memory space in the ram to save whe address such as 0x233828ff21 and if so this(0x233828ff21) address requires a lot of bytes? [question03]
where does this int pointer stores it's type length (4bytes)? [question05]
what happens if i declare a type with longer byte memory allocation such as long long * ptr = &num; [01][02][00][00][00][00][00][00]
since i am pointing a long long to a 4 byte int, can those 4 last already been allocated by another program and in use? can i read it? [question06]
binary are only 0 and 1 and whether one of those(0 or 1) is called a bite? [question07]
one byte is 8 bits right? why am i getting 16 bits 0000000000000001 when converting the number 1 in this website (https://www.rapidtables.com/convert/number/decimal-to-binary.html) shouldn't it be 8? [question08]
Note: char * ptr = &num; should really be unsigned char * ptr = (unsigned char *)&num; to avoid compiler warnings and to ensure that the bytes are treated as unsigned values.
how can i access the first byte of this int pointer? [question01]
If you really want to access the first byte of a pointer, you can use:
unsigned char *ptr2 = (unsigned char *)&ptr;
then ptr2[0] is the first byte of the pointer ptr.
is there a way to see the bites inside the of the first byte([01])? [question02]
I assume you mean the bits inside the first byte. Bits are not directly addressable, so you need an expression (usually with bit-wise operators) to get the value each bit. For example, (ptr[m] >> n) & 1 will be the value of the nth bit of the mth byte of an object (where ptr is an unsigned char * pointing to the start of the object).
where does the pointer save the address? does it have to allocate a memory space in the ram to save whe address such as 0x233828ff21 and if so this(0x233828ff21) address requires a lot of bytes? [question03]
Addresses are stored in pointer variables in the same way as numbers are stored in variables of numeric type. At the CPU instruction level, there is no difference between a stored pointer value and a stored integer value, other than the width.
The most typical sizes of pointer types are 8 bytes or 4 bytes, depending on the target architecture of the compiler.
(There is no question04.)
where does this int pointer stores it's type length (4bytes)? [question05]
It doesn't store the length of the type, but the compiler knows that a TYPE * points to an object that is sizeof(TYPE) bytes long.
what happens if i declare a type with longer byte memory allocation such as long long * ptr = # [01][02][00][00][00][00][00][00] since i am pointing a long long to a 4 byte int, can those 4 last already been allocated by another program and in use? can i read it? [question06]
If the pointer is not correctly aligned for the referenced type (long long) then the behavior is undefined. Otherwise it can be converted back to the original pointer type int *. In any case, accessing *ptr will result in undefined behavior (unless long long is the same width as int, which is not typical).
binary are only 0 and 1 and whether one of those(0 or 1) is called a bite? [question07]
It is called a bit. There is also a type called _Bool. Expressions of type _Bool always have the value 0 or 1.
one byte is 8 bits right? why am i getting 16 bits 0000000000000001 when converting the number 1 in this website (https://www.rapidtables.com/convert/number/decimal-to-binary.html) shouldn't it be 8? [question08]
Who cares what some random web-site displays?
What C calls a "byte" is any type where sizeof(type) is 1, including char, signed char and unsigned char. It is at least 8 bits wide, but is wider than 8 bits on some exotic systems.
A pointer of character type (char *, signed char * or unsigned char *) can be used to access the individual bytes within any object, but that might not be true for pointers of other size 1 types, and is certainly not true for pointer to _Bool (_Bool *)!
• how can i access the first byte of this int pointer? [question01]
Generally, it is preferable to use unsigned char rather than char to access arbitrary bytes, so let’s do that.
After unsigned char *ptr = &num;, ptr is a pointer to unsigned char, and you could access the first byte of the int with *ptr or ptr[0], as in printf("The first byte, in hexadecimal, is 0x%02hhx.\n", *ptr);.
If instead you have int *ptr = &num;, there is no direct way to access the first byte. ptr here is a pointer to an int, and, to access an individual byte, you need a pointer to an unsigned char or other single-byte type. You could convert ptr to a pointer to unsigned char, as with (unsigned char *) ptr, and then you can access the individual byte with * (unsigned char *) ptr.
• is there a way to see the bites inside the of the first byte([01])? [question02]
The C standard does not provide a way to display the individual bits of a byte. Commonly programmers print the values in hexadecimal, as above, and read the bits from the hexadecimal digits. You can also write your own routine to write binary output from a byte.
• where does the pointer save the address? does it have to allocate a memory space in the ram to save whe address such as 0x233828ff21 and if so this(0x233828ff21) address requires a lot of bytes? [question03]
A pointer is a variable like your other int and char variables. It has space of its own in memory where its value is stored. (This model of variables having memory is used to specify the behavior of C programs. When a program is optimized by a compiler, it may change this.)
In current systems, pointers are commonly 32 or 64 bits (four or eight 8-bit bytes), depending on the target architecture. You can find out which with printf("The size of a 'char *' is %zu bytes.\n", sizeof (char *));. (The C standard allows pointers of different types to be different sizes, but that is rare in modern C implementations.)
• where does this int pointer stores it's type length (4bytes)? [question05]
The compiler knows the sizes of pointers. The pointer itself does not store the length of the thing it is pointing to. The compiler simply generates appropriate code when you use the pointer. If you use *ptr to get the value that a pointer points to, the compiler will generate a load-byte instruction if the type of ptr is char *, and it will generate a load-four-byte instruction of the type of ptr is int * (and int is four bytes in your C implementation).
• what happens if i declare a type with longer byte memory allocation such as long long * ptr = # [01][02][00][00][00][00][00][00] since i am pointing a long long to a 4 byte int, can those 4 last already been allocated by another program and in use? can i read it? [question06]
When long long is an eight-byte integer, and you have a long long *ptr that is pointing to a four-byte integer, the C standard does not define the behavior when you attempt to use *ptr.
In general-purpose multi-user operating systems, the memory after the int cannot be allocated by another program (unless this program and the other program have both arranged to share memory). Each process is given its own virtual address space, and their memory is kept separate.
Using this long long *ptr in your program may access memory beyond that of the int. This can cause various types of bugs in your program, including corrupting data and alignment errors.
• binary are only 0 and 1 and whether one of those(0 or 1) is called a bite? [question07]
One binary digit is a “bit”. Multiple binary digits are “bits”.
The smallest group of bits that a particular computer operates on as a unit is a “byte”. The size of a byte can vary; early computers had bytes of different sizes. Modern computers almost all use eight-bit bytes.
If your program includes the header <limits.h>, it defines a macro named CHAR_BIT that provides the number of bits in a byte. It is eight in almost all modern C implementations.
• one byte is 8 bits right? why am i getting 16 bits 0000000000000001 when converting the number 1 in this website (https://www.rapidtables.com/convert/number/decimal-to-binary.html) shouldn't it be 8? [question08]
The web site is not merely converting to one byte.
It seems to show at least 16 bits, choosing the least of 16, 32, or 64 bits that the value fits in as a signed integer type.

I don't understand the data type of the code that inserts the 4-byte address into the array

I don't understand the data type of the code that inserts the 4-byte address into the array. We're doing a buffer overflow attack, and we're inserting a four-byte address into the array from the provided source.
Notice that an error occurs if any of the *(long *) & buf [] is missing. However, I do not understand this code. I would appreciate it if you help me.
*(long *) &test[0] = 0x12345678;
*(long *) &test[4] = 0x12345678;
*(long *) &test[8] = 0x12345678;
I don't know the meaning of *(long *) &test[] here.
Let's analyze *(long *) &test[0] = 0x12345678; in steps (the postfix operators have higher precedence than the prefix operators):
test is either an array of bytes or a pointer to an array of bytes. The code handles both cases the same way.
test[0] is an lvalue: the first element of the byte array test (or possibly the byte array pointed to by the pointer test).
&test[0] is the address of this byte.
(long *)&test[0] is the same address, cast as a pointer to long.
*(long *)&test[0] = 0x12345678 writes a long value to this address, overwriting test[0], test[1], test[2] and test[3] (on systems with 8-bit bytes and 32-bit longs).
To summarize: the code fragment writes sizeof(long) bytes to the beginning of the byte array test.
Note however a number of implicit assumptions:
the size of long can be different from 4. It can even vary from one OS to another for the same processor: sizeof(long) is 4 bytes on 64-bit Windows but 8 bytes on 64-bit linux systems.
the order of bytes when writing a long to memory may differ from one architecture to another: little endian 32-bit CPUs will write the bytes 0x78, 0x56, 0x34 and 0x12 in this order, while big endian CPUs will write the same bytes in the opposite order.
there is no guarantee that test[0] is properly aligned for writing a long value to it. Intel CPUs are configured by default to accept misaligned accesses for standard integer sizes, but most CPUs cannot be configured this way and misaligned access has undefined behavior.
the compiler may take advantage of the strict aliasing rule to optimize accesses to the test array. Since you are modifying via a different effective type, it may be fooled and not reload values from memory:
char test[12] = { 0 };
*(long *)test[0] = 0x12345678;
if (test[0] == 0) {
// the compiler could assume that `test[0]` is still `0`.
}
//an example as follows
int test[5] = {0,1,2,3,4};
//test[0]-->It'value is 0,it's type is int.
//&test[0]-->Its value is the address of test[0],what is its type? int*.
//* &test[0]-->how about it?Its value is 0, its type is int too.
//*(long*)&test[0] -->Its value is 0,but its type is long.

dereference an integer pointer on 64 bit platform

if we dereference an integer pointer, say * (int * )
as we know that integer pointer dominate 8 byte in 64 platform. but integer still takes 4 byte in 64 platform.
what if i want to dereference an pointer where the beginning of its memory contains another pointer address. so actually i want to take the value of the first 8 bytes. will dereference * (int *) get 4 byte or 8byte? i think it should be 4 byte as integer is 4 byte. but how can i get 8 byte in 64 bit platform? without knowing whether the platform is 32 or 64 bit.
Lets make some things clear (these are all platform independent but in MOST cases), if on your system:
sizeof(int) is 4 bytes
sizeof(int*) is 4 on 32bit and 8 on 64bit
sizeof(int**) is 4 on 32bit and 8 on 64bit
When you dereference an int*, you are extracting an int. The original int* may be 8 bytes on a 64bit but you will get 4 bytes from either 32bit or 64bit systems.
When you dereference an int**, you are extracting an int*. The original int** may be 4 bytes on 32bit or 8 bytes on a 64bit, but you will get 4 bytes from a 32bit system and 8 bytes from a 64bit system because you are extracting int*.
I'm not sure if I understand your problem right, but actually I think that you really don't have a problem at all, because the compiler will handle word sizes automatically for you, generating the proper code for each platform. So let's assume that you call a function that returns a pointer to a pointer to an int:
int** ppiValue = SomeFunction ();
If you dereference this pointer, you get a pointer to an int, which will have the proper size on each platform:
int* piValue = *ppiValue;
This will be 8 bytes on a 64-bit processor, or 4 bytes on a 32-bit processor. The compiler is responsible for choosing the right size for the selected target platform. Now let's dereference this pointer:
int iValue = *piValue;
This will be a 4-byte value on both processors. Once again, the compiler is responsible for generating proper machine code instructions.
So don't bother - as long as you rely on strong typing and don't use dangerous typecasts, the compiler will take care of the low-level indirection details.

Why is a pointer to a pointer to a function 8 byte?

I know a pointer to a function is 8 byte because of virtualization but why a pointer to a pointer to a function is 8 byte?
typedef void(*fun())();
sizeof(fun*); // returns 8 byte
If you have a 64-bit system with 8-bit bytes (and it sounds like you do), probably all pointers will be 8 bytes in size. Virtualization doesn't have anything to do with it.
It's because they're both pointers to memory addresses regardless of what kind of data they point to, and you're running on a 64-bit system
If memory addresses were say... 4 bytes, than it would be impossible to have more than 4GB of ram on your computer. there just wouldn't be enough different pointer values.
pointer to a pointer to a function is 8 byte?
it is also a pointer.
char *, int *, float * and etc all these pointers Have same size and also function pointer.
Size of pointer is dependent on architecture.
On most architectures Size of pointer is same In your case 8 bytes(64-bit)
on 32-bit size is 4 bytes,
Adding this based on # Grijesh Chauhan comment.
There have been architectures where pointers to different types have different sizes.
You have a 64-bit machine with a 64-bit address word, which happens to be 8 bytes. A pointer is just a memory address, which because of how many bits are in your address space is 8 bytes.
It would be 4 bytes if you were running a 32 bit OS, or 2 bytes on a 286+DOS.

c: size of void*

I'm a bit confused with a void* pointer in C. Especially after reading this question: Is the sizeof(some pointer) always equal to four?, where one person says there is no guarantee that sizeof(int *) == sizeof(double *)
My question is: is there a guarantee of sizeof(void*) >= sizeof(any other pointer type)?
In other words, can I always assign a some_type* pointer to a void* pointer and then get it back as some_type*?
Only data pointers. void * can hold any data pointer, but not function pointers.
Here is a C FAQ.
void *'s are only guaranteed to hold object (i.e. data) pointers; it
is not portable to convert a function pointer to type void *. (On some
machines, function addresses can be very large, bigger than any data
pointers.)
As for the first part, yes, different types can have pointers of different sizes:
The value stored in the pointer is an address to memory. If you're on a 32-bit system, that pointer into memory is going to be 32 bits (or four bytes) long. If you're on a 64-bit system, that pointer into memory is going to be 64 bits (or eight bytes) long.
The size of the data that holds the location in memory has nothing to do with the size of the data represented at that location in memory.
As for how a char * differs from a double *, the char * can point to any location, but the double * has to point to something along an eight-byte boundary. Larger data has to be aligned according to the rules of the processor you're on. So, pointers to small data are not generally compatible with pointers to large data (e.g. you shouldn't point a double * pointer to a char * address); but you're save going in the other direction (e.g. you can point a char * pointer to a double * address).

Resources