0

So I'm writing my own printf function so I'm using stdarg.h and the system call write(). But I have no idea on how to incorrect %p into my function. Would %X produce the same result?

I have %x done as so:

'x': x=va_arg(argp,argp, unsigned int); 
     char *temp = convert(x,16);
     write(1, temp, lengthOFtemp);
     break;

char *convert(unsigned int, int)
{
static char buf[33];
char *ptr;

ptr=&buf[sizeof(buff)-1];
*ptr='\0';
do
{
*--ptr="0123456789abcdef"[num%base];
num/=base;
}while(num!=0);

return(ptr);
}
Morki
  • 205
  • 1
  • 3
  • 10

2 Answers2

0

The difference between %p and %X is that pointer sizes are platform specific - 8 bytes on 64-bit platforms, 4 bytes on 32-bit platforms. Thus, you must use an 'unsigned long' variable to handle the pointer argument from va_args, not 'unsigned int' which remains 4 bytes on some 64-bit platforms.

Otherwise yes, very much like the %X code you have above.

PQuinn
  • 1,002
  • 6
  • 11
  • Thanks. how would I check the system platform (X-bit) and then run %p? – Morki Feb 13 '13 at 04:58
  • No check needed, just use 'unsigned long'. It will size accordingly for ILP32 and LP64 (32-bit and 64-bit) systems. – PQuinn Feb 13 '13 at 05:04
  • So p=va_arg(argp,argp, unsigned long); will work for both? Then I just have to just do convert(p,16)? – Morki Feb 13 '13 at 05:09
  • You must make sure you read the right number of bytes from the stack with va_arg. Thus, if the parameter is %X, you are expecting an integer which is 4 bytes. If the parameter is %p you are expecting a pointer, which is as I explained. Thus you need different calls to va_arg for each. – PQuinn Feb 13 '13 at 05:15
  • Use `intptr_t` or `uintptr_t` to store a pointer to void (`void *`) as an integer value in a portable manner. – alk Feb 13 '13 at 07:03
0

You might like to use

void * pv = va_arg(va, void*)

to pull the pointer from the variadic argument list.

To safely receive pointers this way the caller of the variadic function, which does the pulling as shown above, needs to pass in pointers as being casted to void *.

Then do the conversion to integer like so:

#include <inttypes.h>
...
uintptr_t uipv = (uintptr_t) pv;

and finally call a conversion function:

char buff[64] = {0};
char * pc = convert_uintptr(uipv, 16);

with:

char * convert_uintptr(uintptr_t uipv, unsigned base); 
alk
  • 68,300
  • 10
  • 92
  • 234