#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.
Related
If a pointer "p" holds the address of a variable "a". if a=12 ( just taking an integer ) . If the address of "a" is 1024 (just an assumption for asking my doubt). That means the value in "p" is 1024. This 1024 is address but it is basically a number . Then why it doesn't work when we declare the integer pointer variable "p" as integer variable "p". like:
int p, a=12;
p=&a;
printf("value of a is : %d", *p );
The example could be properly written (with some additional output) as:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
intptr_t p;
int a = 12;
p = (intptr_t)(void *)&a;
printf("value of a at %" PRIdPTR " is : %d\n", p, *(int *)(void *)p);
return 0;
}
That relies on the following facts:
A pointer to any object can be converted to void * and back to a pointer to the original object type and it will compare equal to the original pointer to the object (so it will still point to it).
A pointer to void can be converted to a intptr_t or a uintptr_t value (by a cast operator) and back again and it will compare equal to the original pointer.
The PRIdPTR macro defined by #include <inttypes.h> expands to a string literal containing a printf conversion specifier (possibly preceded by a length modifier) suitable for printing the value of a parameter of type intptr_t as a signed decimal number. It is being included in the printf format string by string literal concatenation.
A void * pointer value is usually printed using the %p printf format, for example:
printf("value of a at %p is : %d\n", (void *)p, *(int *)(void *)p);
or:
printf("value of a at %p is : %d\n", (void *)&a, a);
To declare p as a pointer to int do it the following way:
int *p; /* p is a pointer to int */
so, with initializers:
int a = 12, /* a is an integer var and it's initialized to 12 */
*p = &a; /* p is an integer pointer and it's initialized to the addreess of a */
or as assignments:
a = 12; /* a is assigned the value 12 */
p = &a; /* p is assigned the address of a */
works, and *p will have the same value as a.
printf("value of a is : *p==%d (or what should be the same: a==%d)", *p, a);
*p means the to take data from the place which p stores.
The * operator when applied to an operand p basically means "read what's on address stored in p and interpret it as the type indicated by the pointer type p is declared as"
You're missing the last part. In your case, p is not a pointer, so the dereference operator does not make sense to use.
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.
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);
I am a first year student in C programming so my skill/knowledge is limited. I am trying to create my own implementation on printf, but I am having trouble with retrieving and printing the address of a variable. With printf, its possible to output the address of a variable with %p, i need to replicate %p somehow.
When storing the address of a variable, the data type is int*, and I cannot figure out how to write this address to the screen(stdout).
For Example:
int i = 123;
int *address = &i;
Now how would I output address(not the value at i)? I have tried using the original printf format specifiers for testing purposes. I tried using %x, %s, %d, %lu... it all gives me an error as I am trying to output an int*(integer pointer).
Can anyone assist me in outputting the address?
You can only inspect the bits of the pointer and print those, using the type unsigned char:
unsigned char* a = ( unsigned char* )address;
for( size_t i = 0 ; i < sizeof( address ) ; i++ )
printf( "%hhu" , a[i] );
Another option, if the pointer is a pointer to an object, is to cast the pointer to types: intptr_t or uintptr_t, but the availability of those types is implementation defined.
If it's for the address of an object you could do the following:
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main(void)
{
int a;
uintptr_t uip = (uintptr_t) ((void*) &a);
printf("address of a = 0x%"PRIXPTR, uip);
}
To print the address of a function you need to go as proposed here.
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.