madraven
madraven

Reputation: 109

Incorrect result for %p when implementation printf

I'm working on my own printf code and I got 2 problems that I hoped you might be able to help me with.

The first one is with the %p option :

This option gives me the pointer address of a void* in hex form. So what I'm doing is this :

void    printp(void *thing)
{
    dectohex((long)&thing, 1);
}  

where dectohex is just a function converting a decimal to hex. The result will always be correct, except for the last 3 characters. Always. For example :

me : 0x5903d8b8 , printf : 0x5903da28.

And these characters don't change very often, whereas the other part changes at each call like its supposed to.

The other problem I have is with the %O option. I can't manage to convert a signed int to an unsigned int. printf prints huge numbers for negative int's, and no casts seems to work since I wouldn't have the place to store it anyways.

EDIT: Thanks sooo much for the answers, so apparently for the first problem i was just a little stupid. For the second question i'm gonna try the different solutions you gave me and update you if i manage to do it.

Again thanks so much for your time and patience, and sorry for the delay in my response, i checked the email alert for any answer but it doesn't work apparently.

REEDIT: After reading your answers to my second question more carefully, i think some of you think i asked about %o or %0. I was really talking about %O as in %lo i think. In the man it tells me "%O : The long int argument is converted to unsigned octal". My problem is before converting the long int to octal, i need to convert it to something unsigned.

Upvotes: 8

Views: 778

Answers (4)

chux
chux

Reputation: 153367

If uintptr_t/intmax_t is defined (it is optional), convert the pointer to that integer type and then print.

Otherwise, if sizeof(uintmax_t) >= sizeof (void *) , convert to uintmax_t. uintmax_t is a required type, but may not be sufficiently large.

void printp(void *thing) {
  uintptr_t j = (uintptr_t) thing;
  char lst[(sizeof j * CHAR_BIT + 3)/ 4 + 1]; // Size needed to print in base 16
  char *p = &lst[sizeof lst] - 1;
  *p = '\0';
  do {
    p--;
    *p = "0123456789ABCDEF"[j%16];
    j /= 16;
  } while (p > lst);
  fputs(p, stdout);
}

The %O problem is likely a sign extension issue. (@mafso) Insure valuables used are unsigned, like unsigned and unsigned long. Without seeing the code difficult to know for sure.

Upvotes: 3

Weather Vane
Weather Vane

Reputation: 34585

About your second question regarding zero-padding and negative integers, which seems entirely separate from the first question about hex output. You can handle negative numbers like this (although in 32-bit it does not work with the value -2147483648 which is 0x80000000).

#include <stdio.h>
#define MAXDIGITS   21

int printint(int value, int zeropad, int width)
{
    int i, z, len = 0;
    char strg [MAXDIGITS+1];
    strg [MAXDIGITS] = 0;

    if (value < 0) {
        value = - value;
        putchar ('-');
        len = 1;
    }

    for (i=MAXDIGITS-1; i>=0; i--) {
        strg [i] = '0' + value % 10;
        if ((value /= 10) == 0)
            break;
    }

    if (zeropad)
        for (z=MAXDIGITS-i; z<width; z++) {
            putchar ('0');
            len++;
        }

    for (; i<MAXDIGITS; i++) {
        putchar (strg [i]);
        len++;
    }
    return len;
}

int main (int argc, char *argv[])
{
    int num = 0, len;
    if (argc > 1) {
        sscanf (argv[1], "%d", &num);
        // try the equivalent of printf("%4d, num);
        len = printint (num, 0, 4);
        printf ("   length %d\n", len);
        // try the equivalent of printf("%04d, num);
        len = printint (num, 1, 4);
        printf ("   length %d\n", len);
    }
    return 0;
}

Upvotes: 0

Ishay Peled
Ishay Peled

Reputation: 2868

About the first issue you're having, just to make sure, you want to print the address of thing (note that thing itself is a pointer) or the address of the origin of thing (the pointer to the pointer thing)?

You're currently printing the pointer to the pointer.

Change

dectohex((long)&thing, 1); 

to

dectohex((long)thing, 1); 

if that is the case.

About the %O problem, can you give a code example?

Upvotes: 2

Mike Crawford
Mike Crawford

Reputation: 2278

You need "unsigned long long" for your cast.

Pointers are unsigned, but long is signed.

The number of bits in any data type is implementation-dependent; however these days it is common for long and unsigned long to be 32 bits.

edit: to be more clear, you can't count on anything about the number of bits in C, C++ or Objective-C, it's always implementation-dependent. For example it was at one time common to have nine bit bytes and thirty-six bit words. That's why the Internet Protocols always specify "octets" - groups of eight bites - rather then "bytes".

That's one advantage of Java, in that the number of bits in each data type is strictly definited.

Upvotes: 1

Related Questions