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
  • 215
  • 1
  • 3
  • 11
  • Related: http://stackoverflow.com/questions/2369541/where-is-p-useful-with-printf – John Carter Feb 13 '13 at 04:45
  • You need to select an integral type that can hold a pointer and cast your pointer to it. This is inherently non-portable. On a 64-bit system you may have to use `unsigned long long int` and `%llX` or similar.On a 32-bit system, `unsigned int` and `%X` may work. – n. m. could be an AI Feb 13 '13 at 04:53
  • How can I check to see if the system is 64 bit or 32 bit? – Morki Feb 13 '13 at 04:54
  • @n.m.: For systems which support ``, including C99 compliant systems and MSVC, you can use `uintptr_t`. This is portable. – Dietrich Epp Feb 13 '13 at 07:19
  • Your sample code doesn't compile, and isn't even close. You have parameters without names, mix of `buf` and `buff`, and more and more. – ugoren Feb 13 '13 at 08:23
  • @DietrichEpp: yes, but what format character corresponds to it? – n. m. could be an AI Feb 13 '13 at 10:47
  • @n.m.: the `PRIxPTR` macro from ``, but I don't think that's relevant because the asker is implementing `printf()` and is writing the conversion conversion code rather than relying on library functions. – Dietrich Epp Feb 13 '13 at 11:17
  • @DietrichEpp: I mean, he cannot portably use an existing integer format of *his own* printf function, or at least it is not trivial. – n. m. could be an AI Feb 13 '13 at 12:24

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
  • 992
  • 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
  • 69,737
  • 10
  • 105
  • 255