Why value of pointer changes after cast? - c

Code:
int main(void) {
register int rsp asm("rsp");
int temp=rsp;
printf("\n (rsp)%p \n", rsp);
printf("\n (temp)%p \n", temp);
printf("\n (void*)(rsp)%p \n", (void*)rsp );
printf("\n (void*)(temp)%p \n", (void*)temp );
return 0;
}
Output:
(rsp)0xffffcbe0
(temp)0xffffcbe0
(void*)(rsp)0xffffffffffffcbe0
(void*)(temp)0xffffffffffffcbe0
I suspect this is a silly question, but why does value of pointer changes after cast? I've tried to cast to different types and i always get same offset.
Thank you.

but why does value of pointer changes after cast?
int and rsp are int, not pointers.
Using "%p" is undefined behavior with int.
printf("\n (rsp)%p \n", rsp); // UB
printf("\n (temp)%p \n", temp); // UB
Yet let us assume the value, converted to unsigned was as printed by OP.
printf("\n (rsp)0x%x \n", (unsigned) rsp); // (rsp)0xffffcbe0
printf("\n (temp)0x%x \n", (unsigned) temp); // (temp)0xffffcbe0
When code coverts a pointer to int as in register int rsp asm("rsp");, it can lose significance #David Wohlferd. When converting an int to a pointer, various conversion mechanisms occur like sign extension to cope with the narrow int. The "%p" have an implementation specific format.
To be clear: OP's code does not certainly print the address of the original asm("rsp"). (Compiler specific extension).
C provides optional integer types (u)intptr_t that provide a conversion from/to an equivalent integer and object pointer. To save an object pointer in an integer, use those types. Unfortunately, C lacks a latching print specifier for printing the value of a non-void* pointer and (u)intptr_t, thus casting in the following.
#include <stdint.h>
#include <stdio.h>
char *s = "rsp";
printf("pointer %p\n", (void *) s);
uintptr_t i_ptr = (uintptr_t) s;
printf("integer 0x%jX\n", (uintmax_t) i_ptr);

Related

Format Specifier: %u vs %d in C

#include<stdio.h>
int main(){
int a = 3;
printf("%u\n",&a);
printf("%d\n",&a);
return 0;
}
I was trying to print address of Variable, "a". Now with usage of two different format specifier, "%u" and "%d", two different memory address is printed which I find it wierd.
So My Question is what difference between two format specifier?
Using the both conversion specifiers to output an address invokes undefined behavior.
From the C Standard (7.21.6.1 The fprintf function)
9 If a conversion specification is invalid, the behavior is
undefined.275) If any argument is not the correct type for the
corresponding conversion specification, the behavior is undefined.
Instead you should use the conversion specifier p as for example
printf( "%p\n", ( void * )&a );
Another approach is to use integer types intptr_t or uintptr_t declared in the header <stdint.h> and to use specifiers PRIdPTR or PRIuPTR or, for example, PRIxPTR declared in the header <inttypes.h> to output assigned values of pointers of the type void *.
Here is a demonstration program.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main( void )
{
int a = 3;
intptr_t p1 = ( intptr_t )( void * )&a;
uintptr_t p2 = ( uintptr_t )( void * )&a;
printf( "&a = %p\n", ( void * )&a );
printf( "&a = %"PRIdPTR "\n", p1 );
printf( "&a = %"PRIuPTR "\n", p2 );
printf( "&a = %#"PRIxPTR "\n", p2 );
}
The program output is
&a = 0x7ffc220b16ec
&a = 140720879638252
&a = 140720879638252
&a = 0x7ffc220b16ec
%d is for signed integers, %u is for unsigned integers.
So, when you print the same value out with %d and with %u, you may get different values, since the bytes you're printing out are being interpreted differently. (Once as a signed integer, once as an unsigned integer.)
Final note, you should use %p ("p" for "pointer") to print out addresses.
Well of course "%u\n" has different address than "%d\n" because these are different values created one after another. Look at ASM:
RDX register will have the same value for both printf calls because of LEA instruction is putting the same address into it.
But what you probably see are the values of RCX register which contains different printf format value address for each printf call.
Now the answer:
%d is signed decimal integer.
%u is unsigned decimal integer.
The problem occurs when there is a printf call. This function changes the value of RDX register which is the memory address of a variable.

how to printf 0x0000000 instead of (nil) and 0x08ffffff instead of 0x8ffffff in c

I am trying to use the stdout stream to print 0x00000000 instead of (nil) and 0x08ffffff instead of 0x8ffffff.
So basically, char *ptr1 = 0x00000000 and char *ptr2 = 0x08ffffff.
When I run
printf("start of address is %p and end of address is %p", ptr1, ptr2);
I get
start of address is (nil) and end of address is 0x8ffffff
I actually found a way around this and I would actually do this:
char *ptr1 = 0x00000000;
char *ptr2 = 0x08ffffff;
printf("start 0x%08x and end 0x%08x\n",ptr1, ptr2);
This generates
start 0x00000000 and end 0x08ffffff
However, the compiler sends the following warning:
warning: format ‘%x’ expects argument of type ‘unsigned int’,
but argument 3 has type ‘void *’ [-Wformat=]
How should I modify printf to adjust the output print?
First, to have any control over how addresses are printed, you must convert them to an integer type. The specifications for printing pointers with %p are inadequate. To do this, you can include <stdint.h> and use the type uintptr_t, which is an unsigned integer type suitable for some work with addresses.
Second, the header <inttypes.h> provides a macro PRIxPTR that provides a printf conversion specifier for printing uintptr_t values in hexadecimal.
Third, you can add a flag 0 and a minimum field width 8 to request the conversion pad with zeros to at least eight digits.
Here is sample code:
#include <inttypes.h>
#include <stdio.h>
#include <stdint.h>
static void PrintAddress(const void *p)
{
uintptr_t u = (uintptr_t) p;
printf("0x%08" PRIxPTR, u);
}
int main(void)
{
char *ptr1 = (char *) 0x00000000;
char *ptr2 = (char *) 0x08ffffff;
printf("Start of address is ");
PrintAddress(ptr1);
printf(" and end of address is ");
PrintAddress(ptr2);
printf(".\n");
}
Better yet, you can adapt the field width to the size of uintptr_t in your C implementation by including <limits.h> and calculating the number of digits needed:
printf("0x%0*" PRIxPTR, ((int) sizeof u * CHAR_BIT + 3) / 4, u);
Note that directly setting pointers to hard-coded constant values, as you do with the initializations of ptr1 and ptr2, is rare. It is generally used in doing special things with hardware. When you are deliberately converting an integer to a pointer, you should use a cast to avoid a compiler warning.

Cast pointer type in C

#include <stdio.h>
int main () {
char c = 'A';
int *int_ptr;
double *double_ptr;
*int_ptr = *(int *)&c;
*double_ptr = *(double *)&c;
printf("Original char = %c \n", c);
printf("Integer pointer = %d \n", *int_ptr);
printf("Double pointer = %f\n", *double_ptr);
return 0;
}
The questing is – Why can't I assign the double_ptr using this code, because it causes segmentation fault, but works fine for integer?
As I understand char is 1-byte long and int is 4-bytes long, so double is 8 bytes-long.
By using expression *(double *)&c I expect the following:
& – Get the memory address of c.
(double *) – pretend that this is a pointer to double.
*() – get the actual value and assign it to double var.
Your code has Undefined Behaviour. Therefore anything could happen.
The UB is because you are casting a char which is one byte to types that are 4 and 8 bytes, which means you are (potentially) accessing memory out of bounds, or with the wrong alignment.
Whether any of this will "work" or "not work" on any particular system is not very relevant, because the code is erroneous.
In your program, typecast of char to int* or double* and then a dereference would get some number of extra bytes from memory, which is undefined behavior.

Integer Pointer Subtraction

I've written a few lines of code predominantly from a book that gets you to declare an integer array, then subtract and pass two addresses from the array to another integer, in order to pass into a printf statement. I'm not sure why, but my actual pointers: aPointer and bPointer seem to be 8 bytes, which poses a problem when I try and pass the subtracted addresses to an integer.
I then changed the latter to a long. The errors are not present in Xcode now, but I cannot print the address of pointerSubtraction properly using the %p specifier which does indeed expect an int and not a long.
int arrayOfInts[10];
for (int i = 0; i < 10; i++) {
arrayOfInts[i] = i;
printf("%d", arrayOfInts[i]);
// prints out 0123456789
}
printf("\n");
int *aPointer = &arrayOfInts[1]; // get address of index 1
int *bPointer = &arrayOfInts[7]; // get address of index 7
long pointerSubtraction = bPointer - aPointer; // subtract index 7 with 1
printf("The size of aPointer is %zu bytes \n", sizeof(aPointer));
printf("The size of aPointer is %zu bytes \n", sizeof(bPointer));
printf("The address of aPointer is %p \n", aPointer);
printf("The address of bPointer is %p \n", bPointer);
printf("The address of final is %p \n", pointerSubtraction);
printf("The value of pointerSubtraction is %ld \n \n", pointerSubtraction);
You might like to use a variable typed ptrdiff_t to store the difference of two pointer values, two addresses.
To printf() out a ptrdiff_t use the length modifier "t". As ptrdiff_t is a signed integer use the conversion specifier "d".
#include <stddef.h>
#include <stdio.h>
int main(void)
{
int a = 0;
int b = 0, * pa = &a;
ptrdiff_t ptr_diff = pa - &b;
printf("pd = %td\n", ptr_diff);
return 0;
}
Also the conversion specifier "p" is only defined for pointers to void. So the printf() calls shall look like:
printf("The address of aPointer is %p \n", (void *) aPointer);
printf("The address of bPointer is %p \n", (void *) bPointer);
Also^2 : The result of adding or substrating a value v from a pointer p is only a valid address if the result pv of the operation still refers to (an element/member of) the object the original pointer p pointed to.
In your code aPointer is the value pointed by *aPointer. Same thing for bPointer.
As the comment says pointerSubtraction is the value obtained by the subtraction, not the address.

What is the meaning of printf("%p", int 1)?

I'm trying to understand the difference between int a and int *a, my first step was to see the value I could get by printi %p of an int a. Of course the compiler shows warnings, but does complete the job for the following code.
#include <stdio.h>
int main() {
int a;
printf("a - declared");
printf("int a = [%d]\n", a); // example - 1745899614
printf("int a pointer = [%p]\n", a); // example - 0x6810505e
a = 10;
printf("a - initialized to value of 10\n");
printf("int a = [%d]\n", a); // exmaple - 10
printf("int a pointer = [%p]\n", a); // example - 0xa
return 0;
}
And as I've mentioned in the source code, I do get a somewhat satisfactory result of 0xa which is equal to 10 in hexadecimal for the value of %p of an int a. But is it actually the case that int points to to that address, or is this just the compiler trying to make sense of %p in such a case?
Where is the memory allocated for ints? How do I test for that?
To print the address of an object named a, use:
printf("The address of a is %p.\n", (void *) &a);
Merely using %p does not tell printf to print the address of the object you use as the argument. You must use the “address of” operator, &, to take the address. Otherwise, you are passing the value of a to printf, not the address of a.
Additionally, it is proper to convert the address to void *, as shown above, because the %p specifier expects a pointer to void. Other types of pointers often work (or appear to work) in many C implementations, but the technical requirement is that a pointer to void be passed.
I imagine the formater ( in printf ), is just interpreting the memory as it is told to. So yeah, "%p" is for pointer, but you gave it an int. You wanted to give it the address of a:
printf( "%p", &a );
for the whole shabang:
int a = 10;
int *b = &a;
printf("value of a: %d\n", a );
printf("location of a: %p\n", &a );
printf("value of b: %p\n", b );
printf("location of b: %p\n", &b );
printf("dereference b: %d\n", *b );
But is it actually the case that int points to to that address, or is
this just the compiler trying to make sense of %p in such a case?
It's the latter. Compiler tries to interpret the integer as a pointer. When you print the value of a using %p compiler finds that the type of a is int and warns you that it's not a pointer.
To print the address of a use:
printf("int a pointer = [%p]\n", (void*)&a);
If a is a pointer (e..g int *a;) then you need to initialize it with a valid address and then you can print:
printf("int a pointer = [%p]\n", (void*)a);
%p is merely a way to tell printf to print your value as an address memory. You're passing the value of 10to it (the value of a) and you get printed this value in the hexadecimal notation 0xa. There is no special interpretation, it is just a formatting option.
If you want the value of the a's address memory printed you can simply do printf("%p", &a);. &a is the address of a.
Or if you want to use a pointer:
int* p;
p = &a;
printf("%p", p); //Prints the p value, that is the a address. Equivalent to printf("%p", &a).

Resources