Casting from a pointer to an integer. What exactly happens? Here are some of the ways i think it could happen:
the C code automatically get the value in the address pointed at by the pointer and inserts it in to the integer.
integer take the address in the pointer and stores the address in the 4 bytes.
Reason i am asking is because changing from 32 bit to 64 bit a pointer can not be cast to a integer any more. That is because the size of memory a pointer takes is 64 bit which is 8 bytes.
A pointer could be pointing to an integer or a long since we do not know the value size the pointer is pointing to.
Is it the pointer address can not be stored in the integer or the value it contains can not be stored in the integer?
Say this simple code. This will not work on 64bit. Even though the pointer is to be treated as an integer it can not be cast. This leads me to believe that it is not taking the value but the address of the pointer and inserting it in to the integer.
In 32 bit the integer takes the pointer address and knows that it has
to take 4 bytes from that pointer address to get the full value.
Is that statement correct?
int main(void){
int number = 3;
int * pnumber = &number;
int castNumber = (int)pnumber;
}
I had a look at this question but still did not make sense what is actually happening under the hood.
http://c-faq.com/ptrs/int2ptr.html
Casting actually says to the conpiler ''take a look at the value here and treat it as another type''. In case of pointer, the address which is kept by pointer becomes now an integer. And yes, in 64 bit mode you cannot store sn address as integer but as long int.
Example:
int k=3;
int *pInt = &k;
long int castPtr = (long int)pInt;
int *another_pInt = (int*)castPtr; // *another_pInt is now 3
EDIT:
Prefer unsigned long over long int. You probably should not care about the sign of the value since it ia an address.
This leads me to believe that it is not taking the value but the address of the pointer and inserting it in to the integer.
Offcourse it is not taking the value that the pointer is pointing at.
To get the value that the pointer is pointing at, you need to do *pnumber(dereference). Using only pnumber you will get the address to which the pointer is pointing to.
When you store a pointer address in an integer data type, the result would depend on cases.
1) If the integer data type and the length of the address are different, then the extra bytes of the address would be lost when storing it in a variable of integer data type.
2) In cases when the size is same, you can store the address in an integer data type. But, i cannot think of a situation when you would need to.
Another point is, if the size of the integer data type and the address is same, you can convert to int and back to the address safely. Read this, See this.
Related
What is the difference between these two code samples? When I print the variable p, it prints the assigned value like below.
int *p;
p = 51;
printf("%d",p);
Output: 51
When I try to assign p=15, am I making memory address "15" in the ram as a pointee to the pointer p? When I try to add int c = 5 +p; it gives output as 71. Why am I getting 71?
I thought that the memory address "15" could store any information of the OS, programs, etc. But it exactly stores int for precise. Though I change the value p = 150; it gives int . How is that possible? What's happening under the hood?! I really don't understand.
Your code is illegal. Formally, it is not C. C language prohibits assigning integral values to pointer types without an explicit cast (with the exception of constant 0)
You can do
p = (int *) 51;
(with implementation-defined effects), but you cannot do
p = 51;
If your compiler allows the latter variant, it is a compiler-specific extension that has nothing to do with standard C language.
Typically, such assignment makes p to point to address 51 in memory.
On top of that, it is illegal to print pointer values with %d format specifier in printf. Either use %p or cast pointer value to proper integer type before using integer-specific format specifiers.
So you're telling that pointer that it points to 0x15. Then, you tell printf to print it as a decimal integer, so it treats it as such.
This reason this works is that on a 32 bit system, a pointer is 4 bytes, which matches the size of an int.
p points to a place in memory. *p is the contents of that space. But you never use the contents, only the pointer.
That pointer can be viewed as just a number, so printf("%d",p) works. When you assign a number to it, it interprets that as an offset into memory (in bytes). However, the pointer is supposed to contain ints, and when you add a number to a pointer, the pointer advances by that many spaces. So p+5 means "point to the int 5 spaces past the one you're pointing at now", which for 4-byte ints means 20 bytes later, hence the 71.
Otherwise, you've said you have a pointer to an int, but you're actually just doing all your stuff to the pointer, not the int it's pointing to.
If you actually put anything into the place you were pointing, you'd run into all kinds of trouble. You need to allocate some unused memory for it (e.g. with malloc), and then read and write values to that memory using *p.
I am learning C programming language these days. I have a question about pointer.
The textbook said pointer stores memory address, and using printf("%p",pointer) we can show where this pointer points in our memory.
But every pointer alse has a type, like int *pointer, long *p and so on. int *pointer means "p is a pointer to int".
My question if we write
int *p,i;
p=&i;
*p=99;
if the pointer only contains the address information, how could the programme know how many digits should be used for storing integer 99? Because an integer could be 16 bits int or 32 bits long.
So I was wondering if an int pointer in memory not only stores address information, but also stores the type information?
Because an integer could be 16 bits int or 32 bits long.
An integer could, but an int could not. Regardless of how large that is exactly in your environment, its size is set in stone (within that environment) and doesn't change at run time. An int * only points to an int, not to a long. Note that if there were any such problems, they would affect int x; equally.
So a pointer really only stores the memory address. Information about the size of the pointee is in the type (just as a non-pointer variable's type tells the compiler how large that variable is).
Make sure you don't confuse what the hardware does with what the compiler does. A pointer is an address to a memory location as far as the hardware is concerned. What that memory location contains, and how long that data is, does not matter. A pointer does not store anything either. It points to a location and that's all. In assembly, this would be similar to using a register that points to a memory location.
The compiler is what tracks the type of data contained at that pointed to location. It is the compiler's job to save you from making type errors. This is where some people complain that you can shoot yourself in the foot with C. It's possible to have a pointer point to a data location where that data can be most anything and any length.
So I was wondering if an int pointer in memory not only stores address information, but also stores the type information?
No, a pointer is a memory address (or in some cases, a value analogous to a memory address). A pointer doesn't contain the data -- it points to the data. In your example, the data is stored in another location (given the name i), and p contains the address of i.
how could the programme know how many digits should be used for storing integer 99?
All the bits (binary digits) of the value type are used to store the stored value. Any given type (like int) has a fixed size. int can have different sizes depending on the system being used, but the size is always determined when the code is compiled. That is, the type int could be 16 bits, 32 bits, 64 bits, or some other size, but the compiler will always use a single size for compiling an entire program.
The type information is retained in the source code code and is used by the compiler to perform type checking and to generate appropriate code, the type is implicit in the generated code rather than explicitly stored as data.
int a[3];
int *j;
a[0]=90;
a[1]=91;
a[2]=92;
j=a;
printf("%d",*j);
printf("%d",&a[0])
printf("%d",&a[1]);
printf("%d",*(j+2));
here the pointer variable j is pointing to a[0],which is 90;and address of a[0] is -20 is on my machine. So j is holding -20.
And the address of a[1] is -18. So to get next variable I should use *(j+2). because j+2 will result in -18. but this is actually going on. To access a[1]. I have to use *(j+1). but j+1=-19. Why is j+1 resulting in -18 ?
Addresses are unsigned. You're printing them as if they were an int, but they're not an int. Use "%p" as the format specifier. That's how you print the address of a pointer.
Additionally, pointer arithmetic is different than the arithmetic you are used to. Internally, adding one to a pointer p increments the address by sizeof *p bytes, i.e., it increments the to the next object.
This is convenient as it saves the programmer from having to always use sizeof when performing arithmetic on a pointer (rarely do you actually want to increment by something other than sizeof *p. When you do, you cast to a char* first.)
pointer addition is not same as simple addition.
It depends on what type of variable the pointer is pointing.
In your case it's an int whose size is machine dependent (you can check of doing sizeof(int)).
So when adding a number to pointer like (j+i) it internally converts to (j+i*sizeof(datatype)) so when you type (j+2) the address is increased the 4 times (assuming int to be 2 bytes) which is not the intended result.
(j+1) will give you the right result (it's like saying point to the next element of int type of data)
Actually the pointer logic works on the basis of the pointer type since integer pointer type moves by size of integer on your machine it moves by the 2 bytes on your machine so p+1 = p+(sizeof(type of pointer))
*(x+y) is always exactly equivalent to x[y] (or y[x]). So to print a[1], you want *(j + 1) (or just j[1]). Note that, in a[1], a is converted to a pointer ... there's no difference between the way a is handled and the way j is handled here.
As range of "unsigned int" is equal to range of " int *" or any pointer since both take 4Bytes in 64bit platform. Can pointer in C can be replaced by unsigned int ??
There is no such guarantee for unsigned int. A special type uintptr_t was introduced in C99 to hold a pointer, regardless of the platform. You need to include <stdint.h> header to use this type.
Absolutely not. Pointers may be eight bytes, not four, on a 64-bit platform! You can sometimes get away with casting between long long and a 64-bit pointer, but even that is questionable.
You cant even be sure that int is 4 Bytes in 64Bit arch! as the type limits are absolutly implementation and enviroment defined. The standard only gives a limitation of which value has to have at least which range. Thats all. int could even be 8 Bytes on 64 Bit it could be 10 Bytes, or it could be 13 Bytes or it could be What ever the enviroment wants its size to have. So ofcourse you can replace it. But it could end in invalid alignments or cause data loss.
As each assignement of types of different size can have.
But at least you can assign a pointer value to an int value. But also this is the only conversion from value type to pointer type which is valid by ISO/IEC9899.
Short answer: no.
Slightly longer answer: there's no guarantee that unsigned int will be able to hold a valid pointer value for a given platform (several people have already pointed out that 64-bit platforms will likely have address values that fall outside of the range of unsigned int). This is further complicated by the fact that pointers to different types may have different sizes and representations.
Pointers don't just encode an address value; they also encode a type. This matters for pointer arithmetic and array subscripting. For example, assume the declarations:
char *cp = 0x4000;
int *ip = 0x4000;
float (*dap)[10] = 0x4000;
All three pointers (cp, ip, dap) start out with the same value: 0x4000. However, adding 1 to each pointer will give different results. Assuming 32-bit int and float types, we'd get:
cp + 1 == 0x4001
ip + 1 == 0x4004;
dap + 1 == 0x4028;
Adding 1 to cp gives us the address of the next char object (0x4001), adding 1 to ip gives us the address of the next int object (0x4004), and adding 1 to dap gives us the address of the next 10-element array of float object (0x4028). This allows us to use the [] operator on each pointer: we can write cp[i] and ip[i] and get the result we expect (the i'th element following the pointer). If you typed all those pointers as unsigned int, however, you wouldn't be able to use the subscript operator, and adding 1 to them would only give you the next byte address, not necessarily the address of the next object.
Let's say you have:
void *a = //some address;
*((int **)(char*)a) = 5
I'm not really clear on what the second line is supposed to be doing... I know that 'a' is casted to a pointer to a char, and then eventually casted to a pointer to a pointer to an int, but it was unclear what dereferencing a pointer to a pointer to an int actually does...
This would be very helpful. Thanks
it is storing the value 5 in "some address", but more precisely, it is storing the value 5 widened to the machine address size in those many bytes starting at "some address".
e. g. if it is a 64-bit machine, it is storing the value 0x0000000000000005 at the 8 bytes starting at "some address"
i don't see why it is doing it in such a complicated way, but who are we to judge the intentions of a programmer hard at work at the end of a long day.
If you dereference a pointer to a pointer to an int you'll get a pointer to an int. Dereferencing means you'll get the object it was pointing at which is in this case a pointer to an int.
Here's an interesting article that explains how to interpret more complex declarations
It's a nonsense, obfuscated way of writing:
void* a = (void*)5;
As we can tell, original code doesn't make any sense. Here is what it does:
Assign an address to a.
Typecast a from void pointer to char pointer.
Wildly typecast the char pointer to a pointer-to-pointer to int.
Take the contents of the pointer-to-pointer, ie the address where an int should be stored.
This address will be stored where a currently stores its address, overwriting it with the address 5.
EDIT: Btw, note that implicit integer to pointer casts are not allowed in C (C99 6.5.4 §3). There must be a cast like in the code above.