I have written
int a;
printf("addr = %p and content = %x\n", (void*)(&a), *(&a));
printf("addr = %p and content = %x\n", (void*)(&a)+1, *(&a)+1);
What I see in the output is
addr = 0x7fffffffde3a and content = 55554810
addr = 0x7fffffffde3b and content = 5555
I expect to see one byte in each address. However, I don't see such thing. Why?
First of all, pointer arithmetic and the dereference operator honors the data type.
Remember, a pointer arithmetic, which generates a pointer one past the last element of an array is valid, but attempt to dereference the generated pointer is undefined behavior.
Attempt to dereference a pointer which points to invalid memory location is undefined behavior.
That said,
Quoting C11,
The unary * operator denotes indirection. [...] If the operand has type ‘‘pointer to type’’, the result has type ‘‘type’’.
So, in your case, *(&a) is the same as a, which is of type int, and the format specifier prints the integer value stored in a.
If you want to see the byte-by-byte value, you need to cast the pointer (address of a) to a char * and then, dereference the pointer to see value stored in each byte.
So, (void*)(&a)+1 should be changed to (char*)(&a)+1 to point to the next byte of memory.
If you want to print bytes, then play with bytes:
use unsigned char* or uint8_t* for pointers
use %hhx to tell printf that input value is character length.
Example:
int a = 0x12345678;
printf("addr = %p and content = %hhx\n", (void*)&a, *(uint8_t*)&a);
printf("addr = %p and content = %hhx\n", ((void*)&a)+1, *((uint8_t*)&a+1));
Result in my little-endian env:
addr = 0xbedbacac and content = 78
addr = 0xbedbacad and content = 56
And don't forget to use *((uint8_t*)&a+1) instead of *(uint8_t*)&a+1. In the example the later would return 79 (78+1).
You've used the formatting directive %x. %x expects an unsigned int. The type of what you pass as the corresponding argument to printf does not change that. printf will read an unsigned int values from its arguments, no matter what you pass to it. If what you pass something that isn't compatible with what printf reads, the behavior of your program is undefined.
You happen to pass an int. An int is not an unsigned int, but it's close enough that when you read an int expecting an unsigned int, the value remains the same if the integer is positive or zero. Negative integers are mapped to a large positive value (UINT_MAX - a on machines using two's complement representation, which is almost all machines).
If you pass a char (signed or not) to printf when it expects an int (signed or not), the behavior is well-defined due to another feature of the C language, which is promotions. Values of integer types that are smaller than int (i.e. char and short) are converted to int¹. So the following program snippet is well-defined and prints the value of a byte at the address p (assuming that … is replaced by a valid pointer value):
unsigned char p = …;
printf("addr = %p and content = %x\n", (void*)p, *p);
*(&a) is the same thing as a. To see just one byte of a, you could cast the pointer &a to the type unsigned char *.
printf("addr = %p and content = %x\n", (void*)&a, *(unsigned char *)(&a));
This will print one byte of the representation of a in memory. Note that the representation depends on the machine's endianness.
Your code snippet doesn't initialize a, so the first call to printf prints whatever garbage happens to be at the location of a in memory at this time. This assumes that int does not have any trap representation, which is the case on virtually all C implementations.
The second call to printf tries to print *(&a)+1. This is just a+1. The output you get is surprising: are you sure you didn't actually run the program with *(&a+1)? This seems to be what you wanted to explore. With *(&a+1), the behavior of your program would be undefined, because this looks one int past a, and a is not in an array of two or more ints. In practice, you'd be likely to get whatever was just below a on the stack, but that's not something you can count on.
If you wanted to see the byte value at an address which is 1 past the start of a in memory, you'd need to cast the pointer to a byte pointer first. When you add an integer n to a pointer, this doesn't add n to the address stored in the pointer, it adds n to the pointer itself. This is only useful when the pointer points to a value inside an array; then p + n points to n array elements past p. In fact, p[n] is equivalent to *(p+n). If you want to add 1 to the address, then you need to obtain a byte pointer, i.e. a pointer to unsigned char. Contrast:
int a[2] = {0x12345678, 0x9abcdef0};
printf("addr = %p and content = %x\n", (unsigned char*)(&a) + 1, *((unsigned char*)(&a) + 1));
printf("addr = %p and content = %x\n", (&a) + 1, *((&a) + 1));
This is well-defined (but with an implementation-defined value since it depends on the platform's endianness) provided that int consists of at least two bytes (which is not strictly mandatory in C, but is the case everywhere except in a few embedded systems).
(void*)(&a) + 1 is not standard C, because void doesn't have a size so it doesn't make sense to move a pointer to void one void element further. However some implementations such as GCC treat void* as byte pointers, just like unsigned char *, so adding an integer to a void* adds this integer to the address stored in the pointer.
¹ Or to unsigned int if the smaller type doesn't fit in a signed int, e.g. on a platform where short and int have the same size.
Related
I thought the ptr's address and a's address is the same with each other. And also I thought the ptr's address is the same with its int value converted from pointer.
But the result of console denied me.What's the reason? How can i understand the result.
#include <stdio.h>
int main() {
int a[5] = {1, 2, 3, 4, 5};
int *ptr = (int *) ((int) a);
printf("a's address: %p \n", a);
printf("ptr's address: %p \n", ptr);
printf("ptr's int value: %x", (int)ptr);
return 0;
}
the console's result is
a's address: 0x7ffee8d30600
ptr's address: 0xffffffffe8d30600
ptr's int value: e8d30600
ps
I have edited the title, and the original ambiguous title is "What is the difference between pointer's address and pointer's int value"
C has a type uintptr_t which lets you store a pointer value:
void *p = …;
uintptr_t u = (uintptr_t)p;
void *q = (void *)q;
// here q is equivalent to p
On many platforms, u stores the address of the object that p point to, just like p does, and u and p have the same representation in memory. This is not an obligation: C implementations are allowed to use a different representation. But using the same representation is the most obvious way to meet the requirement in the C standard.
Note that a conversion from uintptr_t to a pointer type only gives a usable pointer if the uintptr_t value was obtained from a pointer that is still valid. This can be subtle. Even on processor architectures where the representation is the same (which is almost all of them), compilers are allowed to assume that you don't do too crazy things and to optimize accordingly. See responses to the Cerberus survey for some examples.
In your case, you didn't try to store the pointer value in an uintptr_t, you tried to store it in an int. This failed because on your platform, int is too small to store a pointer value. Evidently, on your platform, pointers are 64-bit values and int are 32-bit values. This is a very common arrangement.
a is the address of the array. (It's a pointer to the first element of the array, and on your platform a pointer is just represented by an address.). In this particular run, it's 0x7ffee8d30600. Nothing remarkable there.
(int) a converts the address of a to an int value. This is implementation-defined. Your implementation does the usual thing: since int is too small, it truncates the value. Truncating the address above to an unsigned 32-bit value yields 0xe8d30600. To get a signed value, the most significant bit becomes the sign bit, so a happens to be negative: a is -388823552.
p is (int *) ((int) a). This conversion is again implementation-defined, and your implementation again does the same thing as most. It takes the 32-bit signed int value -388823552, extends it to the desired width and shifts it to the unsigned range, yielding 264 - 388823552 = 0xffffffffe8d30600.
(int)p applies the same truncation process as (int)a above, and again yields -388823552. But you're using the %x specifier to print it out, so this value is converted to unsigned (a 32-bit type on your platform), which gives the value 232 - 388823552 = 0xe8d30600.
Not really what you are trying to achieve here. An int only contains a 32-bit value. Thus, (int)ptr will only return a 32-bit value of ptr's address, which is the lower 4 bytes you get.
I have understand it. The machine is based with 64bit address. Converting the address to int value will loss the upper value of address. So here the a's address is different from ptr's address.
If to use pointer in C++, we can use intptr_t or preferably uintptr_t
Hi im a bit confused in String formats in C.
can someone explains me what is the output of every print of typed here?
printf("%p", pointer);
printf("%x", pointer);
printf("%x", &pointer);
%p means “print a pointer.” You should pass it a pointer that has been converted to void *. %x means “print an unsigned int in hexadecimal.” You should pass it an unsigned int; it is not correct to pass it a pointer.
Suppose we have:
char *pointer = "Hello";
char array[] = "World";
Then, in:
printf("%p", (void *) pointer);
printf("%p", (void *) array);
The value of pointer will be printed in some implementation-defined manner. (It should show you the address that is stored in pointer.)
In the second printf, the array array will be converted to a pointer to its first element, and the value of this pointer will be printed in the implementation-defined manner.
Note that I inserted casts to (void *). This is the proper way to use %p.
In:
printf("%x", (unsigned) pointer);
printf("%x", (unsigned) array);
The value of pointer will be converted to an unsigned int. The result of this conversion is implementation-defined. It should not be surprising, but it may be different from what you see with %p. Additionally, an unsigned int may be too narrow to contain the full value of the pointer, in which case some information will be lost.
After this conversion, the first statement will print the value in hexadecimal (without a leading “0x”, whereas using %p often does include a leading “0x”). The second statement will again convert array to a pointer to its first element, then convert that to unsigned int, and then print that in hexadecimal.
If unsigned int is wide enough, it is possible, even not unlikely, that the values printed by this method will show the same hexadecimal values as shown by the %p method, but you cannot rely on that.
Note that printing these using %x without the cast to unsigned has behavior not defined by the C standard—it is an error to pass a pointer for a %x specification. You must convert it first. Your original code, without the cast, could result in the value being printed coming from some arbitrary data not related to the pointer, or it could have caused your program to abort, or it could have printed the correct address, or it could have done something else—the behavior is not defined.
In:
printf("%x", (unsigned) &pointer);
printf("%x", (unsigned) &array);
The address of pointer, rather than its value, will be converted to an unsigned int and then printed in hexadecimal. This will almost certainly be different than the result of printing pointer.
For &array, the address of the array will be converted to unsigned. Unlike the previous statements, array is not converted to a pointer to its first element. This is because & is a special operator that suppresses this conversion. It returns the address of the array.
The address of the array is the “same” as the address of its first element, because, in memory, the array starts where its first element starts. However, the pointers may have different representations, and it is possible that converting &array to unsigned int may produce a different value than converting array to unsigned int. Nonetheless, in most C implementations, they produce the same value, so you will see the same result for printf("%x", (unsigned) &array); as you did for printf("%x", (unsigned) array);.
first is for pointers and the second one for integers even if the result very often will be the same. And this is explaining everything. If you want to print pointer %p if integer %x.
All other deliberations are wrong as using wrong format specifier invokes the UB.
I've read several posts about casting int pointers to char pointers but i'm still confused on one thing.
I understand that integers take up four bytes of memory (on most 32 bit machines?) and characters take up on byte of memory. By casting a integer pointer to a char pointer, will they both contain the same address? Does the cast operation change the value of what the char pointer points to? ie, it only points to the first 8 bits of an integers and not all 32 bits ? I'm confused as to what actually changes when I cast an int pointer to char pointer.
By casting a integer pointer to a char pointer, will they both contain the same address?
Both pointers would point to the same location in memory.
Does the cast operation change the value of what the char pointer points to?
No, it changes the default interpretation of what the pointer points to.
When you read from an int pointer in an expression *myIntPtr you get back the content of the location interpreted as a multi-byte value of type int. When you read from a char pointer in an expression *myCharPtr, you get back the content of the location interpreted as a single-byte value of type char.
Another consequence of casting a pointer is in pointer arithmetic. When you have two int pointers pointing into the same array, subtracting one from the other produces the difference in ints, for example
int a[20] = {0};
int *p = &a[3];
int *q = &a[13];
ptrdiff_t diff1 = q - p; // This is 10
If you cast p and q to char, you would get the distance in terms of chars, not in terms of ints:
char *x = (char*)p;
char *y = (char*)q;
ptrdiff_t diff2 = y - x; // This is 10 times sizeof(int)
Demo.
The int pointer points to a list of integers in memory. They may be 16, 32, or possibly 64 bits, and they may be big-endian or little endian. By casting the pointer to a char pointer, you reinterpret those bits as characters. So, assuming 16 bit big-endian ints, if we point to an array of two integers, 0x4142 0x4300, the pointer is reinterpreted as pointing to the string "abc" (0x41 is 'a', and the last byte is nul). However if integers are little endian, the same data would be reinterpreted as the string "ba".
Now for practical purposes you are unlikely to want to reinterpret integers as ascii strings. However its often useful to reinterpret as unsigned chars, and thus just a stream of raw bytes.
Casting a pointer just changes how it is interpreted; no change to its value or the data it points to occurs. Using it may change the data it points to, just as using the original may change the data it points to; how it changes that data may differ (which is likely the point of doing the casting in the first place).
A pointer is a particular variable that stores the memory address where another variable begins. Doesnt matter if the variable is a int or a char, if the first bit has the same position in the memory, then a pointer to that variable will look the same.
the difference is when you operate on that pointer. If your pointer variable is p and it's a int pointer, then p++ will increase the address that it contains of 4 bytes.
if your pointer is p and it's a char pointer, then p++ will increase the address that it contains of 1 byte.
this code example will help you understand:
int main(){
int* pi;
int i;
char* pc;
char c;
pi = &i;
pc = &c;
printf("%p\n", pi); // 0x7fff5f72c984
pi++;
printf("%p\n", pi); // 0x7fff5f72c988
printf("%p\n", pc); // 0x7fff5f72c977
pc++;
printf("%p\n", pc); // 0x7fff5f72c978
}
I can't understand the output of this program .
What I get of it is , that , first of all , the pointers p, q ,r ,s were pointing towards null .
Then , there has been a typecasting . But how the heck , did the output come as 1 4 4 8 . I might be very wrong in my thoughts . So , please correct me if I am wrong .
int main()
{
int a, b, c, d;
char* p = (char*)0;
int *q = (int *)0;
float* r = (float*)0;
double* s = (double*)0;
a = (int)(p + 1);
b = (int)(q + 1);
c = (int)(r + 1);
d = (int)(s + 1);
printf("%d %d %d %d\n", a, b, c, d);
_getch();
return 0;
}
Pointer arithmetic, in this case adding an integer value to a pointer value, advances the pointer value in units of the type it points to. If you have a pointer to an 8-byte type, adding 1 to that pointer will advance the pointer by 8 bytes.
Pointer arithmetic is valid only if both the original pointer and the result of the addition point to elements of the same array object, or just past the end of it.
The way the C standard describes this is (N1570 6.5.6 paragraph 8):
When an expression that has integer type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If the
pointer operand points to an element of an array object, and the array
is large enough, the result points to an element offset from the
original element such that the difference of the subscripts of the
resulting and original array elements equals the integer expression.
[...]
If both the pointer operand and the result point to elements of the
same array object, or one past the last element of the array object,
the evaluation shall not produce an overflow; otherwise, the behavior
is undefined. If the result points one past the last element of the
array object, it shall not be used as the operand of a unary *
operator that is evaluated.
A pointer just past the end of an array is valid, but you can't dereference it. A single non-array object is treated as a 1-element array.
Your program has undefined behavior. You add 1 to a null pointer. Since the null pointer doesn't point to any object, pointer arithmetic on it is undefined.
But compilers aren't required to detect undefined behavior, and your program will probably treat a null pointer just like any valid pointer value, and perform arithmetic on it in the same way. So if the null pointer points to address 0 (this is not guaranteed, BTW, but it's very common), then adding 1 to it will probably give you a pointer to address N, where N is the size in bytes of the type it points to.
You then convert the resulting pointer to int (which is at best implementation-defined, will lose information if pointers are bigger than int, and may yield a trap representation) and you print the int value. The result, on most systems, will probably show you the sizes of char, int, float, and double, which are commonly 1, 4, 4, and 8 bytes, respectively.
Your program's behavior is undefined, but the way it actually behaves on your system is typical and unsurprising.
Here's a program that doesn't have undefined behavior that illustrates the same point:
#include <stdio.h>
int main(void) {
char c;
int i;
float f;
double d;
char *p = &c;
int *q = &i;
float *r = &f;
double *s = &d;
printf("char: %p --> %p\n", (void*)p, (void*)(p + 1));
printf("int: %p --> %p\n", (void*)q, (void*)(q + 1));
printf("float: %p --> %p\n", (void*)r, (void*)(r + 1));
printf("double: %p --> %p\n", (void*)s, (void*)(s + 1));
return 0;
}
and the output on my system:
char: 0x7fffa67dc84f --> 0x7fffa67dc850
int: 0x7fffa67dc850 --> 0x7fffa67dc854
float: 0x7fffa67dc854 --> 0x7fffa67dc858
double: 0x7fffa67dc858 --> 0x7fffa67dc860
The output is not as clear as your program's output, but if you examine the results closely you can see that adding 1 to a char* advances it by 1 byte, an int* or float* by 4 bytes, and a double* by 8 bytes. (Other than char, which by definition has a size of 1 bytes, these may vary on some systems.)
Note that the output of the "%p" format is implementation-defined, and may or may not reflect the kind of arithmetic relationship you might expect. I've worked on systems (Cray vector computers) where incrementing a char* pointer would actually update a byte offset stored in the high-order 3 bits of the 64-bit word. On such a system, the output of my program (and of yours) would be much more difficult to interpret unless you know the low-level details of how the machine and compiler work.
But for most purposes, you don't need to know those low-level details. What's important is that pointer arithmetic works as it's described in the C standard. Knowing how it's done on the bit level can be useful for debugging (that's pretty much what %p is for), but is not necessary to writing correct code.
Adding 1 to a pointer advances the pointer to the next address appropriate for the pointer's type.
When the (null)pointers+1 are recast to int, you are effectively printing the size of each of the types being pointed to by the pointers.
printf("%d %d %d %d\n", sizeof(char), sizeof(int), sizeof(float), sizeof(double) );
does pretty much the same thing. If you want to increment each pointer by only 1 BYTE, you'll need to cast them to (char *) before incrementing them to let the compiler know
Search for information about pointer arithmetic to learn more.
You're typecasting the pointers to primitive datatypes rather type casting them to pointers themselves and then using * (indirection) operator to indirect to that variable value. For instance, (int)(p + 1); means p; a pointer to constant, is first incremented to next address inside memory (0x1), in this case. and than this 0x1 is typecasted to an int. This totally makes sense.
The output you get is related to the size of each of the relevant types. When you do pointer arithmetic as such, it increases the value of the pointer by the added value times the base type size. This occurs to facilitate proper array access.
Because the size of char, int, float, and double are 1, 4, 4, and 8 respectively on your machine, those are reflected when you add 1 to each of the associated pointers.
Edit:
Removed the alternate code which I thought did not exhibit undefined behavior, which in fact did.
I am doing some experiments to see how C allocates variables on the stack. I am getting some odd behavior with the following code. C appears to be growing the stack downward, so in the following example, the char c is allocated in the byte immediately before the short s. I then create an int pointer bigRandP and point it at the same location occupied by c, so the "int" it sees overlaps with the space on the stack occupied by s. I then try to assign something to the location referenced by the int pointer.
unsigned short nameSum = 0;
unsigned char smallRand = 0;
unsigned int* bigRandP;
//The "int" pointed to by iP should overlap s
bigRandP = (unsigned int*)(&smallRand);
printf("%p %p %p\n", &nameSum, &smallRand, bigRandP);
printf("%u %u %u\n", smallRand, nameSum, *bigRandP);
*bigRandP = 0;
printf("%p %p %p\n", &nameSum, &smallRand, bigRandP);
printf("%u %u %u\n", smallRand, nameSum, *bigRandP);
0028FF1A 0028FF19 0028FF19
0 0 419430400
0028FF1A 0028FF19 0028FF00
0 0 4210788
The printed results are interesting. Not only does the assignment fail (the int pointed to by bigRandP is not set to 0), the int pointer itself is silently relocated to point somewhere else further down the stack. What is going on? Is this the C compiler's way of keeping me from overwriting other variables with overlapping pointers?
bigRandP is a pointer to unsigned int.
You pointed it to an unsigned char object, then you modified the unsigned int object that bigRandP points to.
Apparently smallRand and bigRandP are stored close to each other in memory. By trying to modify sizeof (unsigned int) bytes of a 1-byte object, you clobbered part of the pointer object itself.
Bottom line: Your program's behavior is undefined.
Also, though this probably isn't related to the behavior you're seeing, the %p format requires a void* argument. If you want to print some other type of pointer, you should convert it to void*:
printf("%p %p %p\n", (void*)&nameSum, (void*)&smallRand, (void*)bigRandP);
It's likely to "work" with or without the casts on systems where all pointers have the same representation, but the version with the casts is more correct on all systems.