printf() and void *

Discussion in 'C Programming' started by Ioannis Vranos, Mar 2, 2008.

  1. I recall from previous discussions here, that we must cast a non-void
    pointer to void * before printing its value with printf("%p"). Is it
    true, and if yes why?
     
    Ioannis Vranos, Mar 2, 2008
    #1
    1. Advertising

  2. On Sun, 02 Mar 2008 19:59:19 +0200, Ioannis Vranos wrote:
    > I recall from previous discussions here, that we must cast a non-void
    > pointer to void * before printing its value with printf("%p"). Is it
    > true, and if yes why?


    Except for function pointers, which can't be printed portably at all, it
    is true. There are no implicit conversions from other pointer types to
    void * in the variable arguments of a function, so if any pointer type
    would be accepted, how could printf know which one was passed?
     
    Harald van Dijk, Mar 2, 2008
    #2
    1. Advertising

  3. Harald van D?k said:

    > On Sun, 02 Mar 2008 19:59:19 +0200, Ioannis Vranos wrote:
    >> I recall from previous discussions here, that we must cast a non-void
    >> pointer to void * before printing its value with printf("%p"). Is it
    >> true, and if yes why?

    >
    > Except for function pointers, which can't be printed portably at all, it
    > is true.


    Well, no pointer value can be printed portably, since the output associated
    with %p is implementation-defined. But if you mean there's no *technique*
    for printing a function pointer value in ISO C, I must disagree. (If you
    simply mean that there's no printf format specifier for it, then of course
    you're right.)

    #include <stdio.h>

    int main(void)
    {
    int (*mp)(void) = main;
    unsigned char *ucp = (unsigned char *)&mp;
    size_t len = sizeof mp;
    while(len--)
    {
    printf("%02X", *ucp++);
    }
    puts("");

    return 0;
    }

    <snip>

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -http://www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
     
    Richard Heathfield, Mar 2, 2008
    #3
  4. Richard Heathfield <> writes:
    > Harald van D?k said:
    >> On Sun, 02 Mar 2008 19:59:19 +0200, Ioannis Vranos wrote:
    >>> I recall from previous discussions here, that we must cast a non-void
    >>> pointer to void * before printing its value with printf("%p"). Is it
    >>> true, and if yes why?

    >>
    >> Except for function pointers, which can't be printed portably at all, it
    >> is true.

    >
    > Well, no pointer value can be printed portably, since the output associated
    > with %p is implementation-defined. But if you mean there's no *technique*
    > for printing a function pointer value in ISO C, I must disagree. (If you
    > simply mean that there's no printf format specifier for it, then of course
    > you're right.)
    >
    > #include <stdio.h>
    >
    > int main(void)
    > {
    > int (*mp)(void) = main;
    > unsigned char *ucp = (unsigned char *)&mp;
    > size_t len = sizeof mp;
    > while(len--)
    > {
    > printf("%02X", *ucp++);
    > }
    > puts("");
    >
    > return 0;
    > }


    On a system with CHAR_BIT > 8, the above would wor, but it could
    produce ambiguous results. For example, the output "12345" could be
    result of bytes 0x123 and 0x45 or 0x12 and 0x345.

    I don't believe there are any hosted implementations (i.e., ones
    required to support <stdio.h> with CHAR_BIT > 8), so this is unlikely
    to be an issue in practice -- though the systems, mostly DSPs, that do
    have CHAR_BIT > 8 may well support stdio even though they're not
    required to.

    Another possible issue with the above is the order in which it prints
    the bytes. On one system, I ran the above code with an added line:

    printf("main = %p\n", (void*)main); /* non-portable extension */

    and got:

    A4830408
    main = 0x80483a4

    There are always tradeoffs. If you want to ensure that the output is
    sensible for the platform's address representation, *and* if the
    implementation supports converting a function pointer to void*, *and*
    if you don't mind your code being non-portable, you can use "%p" with
    a cast. On systems that don't support the conversion, the code is
    likely to be rejected rather than to misbehave silently.

    If you want to get *really* fancy, you can write a function that tests
    the byte ordering of some integer type, assume that that corresponds
    to the pointer representation, and use that to determine the order in
    which to display the bytes. And you can insert, say, a ':' character
    between successive bytes to ensure it's unambiguous (or you can check
    the value of CHAR_BIT).

    --
    Keith Thompson (The_Other_Keith) <>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Mar 2, 2008
    #4
  5. On Sun, 02 Mar 2008 18:33:12 +0000, Richard Heathfield wrote:
    > Harald van D?k said:
    >> On Sun, 02 Mar 2008 19:59:19 +0200, Ioannis Vranos wrote:
    >>> I recall from previous discussions here, that we must cast a non-void
    >>> pointer to void * before printing its value with printf("%p"). Is it
    >>> true, and if yes why?

    >>
    >> Except for function pointers, which can't be printed portably at all,
    >> it is true.

    >
    > Well, no pointer value can be printed portably, since the output
    > associated with %p is implementation-defined. But if you mean there's no
    > *technique* for printing a function pointer value in ISO C, I must
    > disagree. (If you simply mean that there's no printf format specifier
    > for it, then of course you're right.)
    >
    > #include <stdio.h>
    >
    > int main(void)
    > {
    > int (*mp)(void) = main;
    > unsigned char *ucp = (unsigned char *)&mp; size_t len = sizeof mp;
    > while(len--)
    > {
    > printf("%02X", *ucp++);
    > }
    > puts("");
    >
    > return 0;
    > }
    >
    > <snip>


    Your example prints the representation of a function pointer, not its
    value. If multiple function pointer representations exist for one value,
    there is no portable way to print the value in such a way that the
    different representations become indistinguishable.
     
    Harald van Dijk, Mar 2, 2008
    #5
  6. Harald van Dijk wrote:
    > On Sun, 02 Mar 2008 19:59:19 +0200, Ioannis Vranos wrote:
    >> I recall from previous discussions here, that we must cast a non-void
    >> pointer to void * before printing its value with printf("%p"). Is it
    >> true, and if yes why?

    >
    > Except for function pointers, which can't be printed portably at all, it
    > is true. There are no implicit conversions from other pointer types to
    > void * in the variable arguments of a function, so if any pointer type
    > would be accepted, how could printf know which one was passed?



    In printf() in general, if we want to print the numeric value of a
    signed char and of an unsigned char using %d and %u respectively, should
    we cast the variable value to the expected type (int and unsigned
    respectively)?
     
    Ioannis Vranos, Mar 2, 2008
    #6
  7. Ioannis Vranos

    santosh Guest

    Ioannis Vranos wrote:

    > Harald van Dijk wrote:
    >> On Sun, 02 Mar 2008 19:59:19 +0200, Ioannis Vranos wrote:
    >>> I recall from previous discussions here, that we must cast a
    >>> non-void pointer to void * before printing its value with
    >>> printf("%p"). Is it true, and if yes why?

    >>
    >> Except for function pointers, which can't be printed portably at all,
    >> it is true. There are no implicit conversions from other pointer
    >> types to void * in the variable arguments of a function, so if any
    >> pointer type would be accepted, how could printf know which one was
    >> passed?

    >
    >
    > In printf() in general, if we want to print the numeric value of a
    > signed char and of an unsigned char using %d and %u respectively,
    > should we cast the variable value to the expected type (int and
    > unsigned respectively)?


    It shouldn't be necessary, at least as far as I can see.
     
    santosh, Mar 2, 2008
    #7
  8. Ioannis Vranos

    Micah Cowan Guest

    Ioannis Vranos <> writes:

    > Harald van Dijk wrote:
    >> On Sun, 02 Mar 2008 19:59:19 +0200, Ioannis Vranos wrote:
    >>> I recall from previous discussions here, that we must cast a non-void
    >>> pointer to void * before printing its value with printf("%p"). Is it
    >>> true, and if yes why?

    >>
    >> Except for function pointers, which can't be printed portably at
    >> all, it is true. There are no implicit conversions from other
    >> pointer types to void * in the variable arguments of a function, so
    >> if any pointer type would be accepted, how could printf know which
    >> one was passed?

    >
    >
    > In printf() in general, if we want to print the numeric value of a
    > signed char and of an unsigned char using %d and %u respectively,
    > should we cast the variable value to the expected type (int and
    > unsigned respectively)?


    If you're going to use %u for unsigned char, yeah, a cast is a good
    idea for maximally correct code. Using %d for either char, signed char
    or unsigned char does not require a cast, as it will be promoted to
    int in any case.

    --
    Micah J. Cowan
    Programmer, musician, typesetting enthusiast, gamer...
    http://micah.cowan.name/
     
    Micah Cowan, Mar 2, 2008
    #8
  9. Keith Thompson <> wrote:
    > Richard Heathfield <> writes:
    > > #include <stdio.h>
    > >
    > > int main(void)
    > > {
    > >   int (*mp)(void) = main;
    > >   unsigned char *ucp = (unsigned char *)&mp;
    > >   size_t len = sizeof mp;
    > >   while(len--)
    > >   {
    > >     printf("%02X", *ucp++);
    > >   }
    > >   puts("");

    >
    > >   return 0;
    > > }

    >
    > On a system with CHAR_BIT > 8, the above would wor[k],
    > but it could produce ambiguous results.  For example,
    > the output "12345" could be result of bytes 0x123 and
    > 0x45 or 0x12 and 0x345.


    Then fix it dear Henry. :)

    #define CHAR_NIBBLES ((CHAR_BIT + 3)/4)
    printf("%0*X", CHAR_NIBBLES, 0u + *ucp++);

    <snip>
    > Another possible issue with the above is the order in
    > which it prints the bytes.  On one system, I ran the
    > above code with an added line:
    >
    >     printf("main = %p\n", (void*)main);
    > /* non-portable extension */
    >
    > and got:
    >
    > A4830408
    > main = 0x80483a4
    >
    > There are always tradeoffs.


    Neither is intelligible IMO. But the advantage of
    printing bytes is that you _know_ the format (and
    width) of the output. That is quite significant in
    the hand full of cases where you actually _want_
    to print an address!

    --
    Peter
     
    Peter Nilsson, Mar 3, 2008
    #9
  10. Harald van D©¦k <> wrote:
    > ... [the] example prints the representation of a function
    > pointer, not its value.


    It's value is determined by the representation.

    > If multiple function pointer representations exist for
    > one value, there is no portable way to print the value
    > in such a way that the different representations become
    > indistinguishable.


    How is this any different to the case for %p? The only
    thing you're guaranteed is that if you read via %p you'll
    get a pointer that compares equal to the original.

    The 'hex dump' approach has the same guarantee.

    --
    Peter
     
    Peter Nilsson, Mar 3, 2008
    #10
  11. On Sun, 02 Mar 2008 19:45:29 -0800, Peter Nilsson wrote:
    > Harald van Dijk <> wrote:
    >> ... [the] example prints the representation of a function pointer, not
    >> its value.

    >
    > It's value is determined by the representation.


    Of course, but that's true for all types. Should we start printing 1.01 as
    a series of bytes too, then?

    >> If multiple function pointer representations exist for one value, there
    >> is no portable way to print the value in such a way that the different
    >> representations become indistinguishable.

    >
    > How is this any different to the case for %p? The only thing you're
    > guaranteed is that if you read via %p you'll get a pointer that compares
    > equal to the original.


    If you print the same value to printf twice, you can be sure you get the
    same string twice. If you print the representation of two identical values
    twice, you can't be sure you get the same string twice.
     
    Harald van Dijk, Mar 3, 2008
    #11
  12. Ioannis Vranos

    Guest

    On Mar 3, 12:19 am, Harald van D©¦k <> wrote:
    > On Sun, 02 Mar 2008 19:45:29 -0800, Peter Nilsson wrote:
    > > Harald van D©¦k <> wrote:
    > >> ... [the] example prints the representation of a function pointer, not
    > >> its value.

    >
    > > It's value is determined by the representation.

    >
    > Of course, but that's true for all types. Should we start printing 1.01 as
    > a series of bytes too, then?


    Isn't it what "binary file formats" is about?

    > >> If multiple function pointer representations exist for one value, there
    > >> is no portable way to print the value in such a way that the different
    > >> representations become indistinguishable.

    >
    > > How is this any different to the case for %p? The only thing you're
    > > guaranteed is that if you read via %p you'll get a pointer that compares
    > > equal to the original.

    >
    > If you print the same value to printf twice, you can be sure you get the
    > same string twice. If you print the representation of two identical values
    > twice, you can't be sure you get the same string twice.


    You can not be sure that you'll get two identical
    strings from printf("%p\n%p\n", p, p). printf() is
    "better" only in that scanf() will be able to read
    the string back; the "quality" of output may be
    "worse" or "better" in either case.

    Anyway, it was about function pointers, for which
    printf() doesn't work, so...

    Yevgen
     
    , Mar 3, 2008
    #12
  13. Peter Nilsson <> writes:
    > Keith Thompson <> wrote:
    >> Richard Heathfield <> writes:
    >> > #include <stdio.h>
    >> >
    >> > int main(void)
    >> > {
    >> >   int (*mp)(void) = main;
    >> >   unsigned char *ucp = (unsigned char *)&mp;
    >> >   size_t len = sizeof mp;
    >> >   while(len--)
    >> >   {
    >> >     printf("%02X", *ucp++);
    >> >   }
    >> >   puts("");

    >>
    >> >   return 0;
    >> > }

    >>
    >> On a system with CHAR_BIT > 8, the above would wor[k],
    >> but it could produce ambiguous results.  For example,
    >> the output "12345" could be result of bytes 0x123 and
    >> 0x45 or 0x12 and 0x345.

    >
    > Then fix it dear Henry. :)
    >
    > #define CHAR_NIBBLES ((CHAR_BIT + 3)/4)
    > printf("%0*X", CHAR_NIBBLES, 0u + *ucp++);


    Sure. But using printing hex digits per byte likely *is* the best
    format when CHAR_BIT==8.

    > <snip>
    >> Another possible issue with the above is the order in
    >> which it prints the bytes.  On one system, I ran the
    >> above code with an added line:
    >>
    >>     printf("main = %p\n", (void*)main);
    >> /* non-portable extension */
    >>
    >> and got:
    >>
    >> A4830408
    >> main = 0x80483a4
    >>
    >> There are always tradeoffs.

    >
    > Neither is intelligible IMO. But the advantage of
    > printing bytes is that you _know_ the format (and
    > width) of the output. That is quite significant in
    > the hand full of cases where you actually _want_
    > to print an address!


    Sure, but using "%p" means that the implementer chooses a format
    that's intended to make sense in terms of the addressing structure of
    the machine. If I print the addresses of two functions using the
    non-portable trick of casting to void* and using "%p", and I and get
    "0x80483a4" and "0x80483b8", then that might tell me something about
    the relationship between the functions, and it's very likely to match
    the information in a link map. If I see "A4830480" and "B8830480",
    it's a bit harder to see that relationship, or even to tell whether
    the addresses make sense.

    --
    Keith Thompson (The_Other_Keith) <>
    Nokia
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Mar 3, 2008
    #13
  14. Ioannis Vranos

    David Tiktin Guest

    On 02 Mar 2008, Richard Heathfield <> wrote:

    > Harald van D?k said:
    >
    >> On Sun, 02 Mar 2008 19:59:19 +0200, Ioannis Vranos wrote:
    >>> I recall from previous discussions here, that we must cast a
    >>> non-void pointer to void * before printing its value with
    >>> printf("%p"). Is it true, and if yes why?

    >>
    >> Except for function pointers, which can't be printed portably at
    >> all, it is true.

    >
    > Well, no pointer value can be printed portably, since the output
    > associated with %p is implementation-defined.


    I'm a little unclear on the point you're making here. I would have
    said that the code:

    #include <stdio.h>
    #include <limits.h>

    int main(void)
    {
    printf("%d\n", INT_MAX);

    return 0;
    }

    is a completely portable way to print the value of INT_MAX even
    though what's printed is obviously implementation defined. I guess I
    generally think of "portable" as meaning "will do 'the right thing'
    on all platforms" so using %p is the portable way to print non-
    function pointers which have been cast to void *. What happens when
    you write to a text file is another example. Can't you write to a
    text file portably in C even though the result is implementation
    defined?

    Dave

    --
    D.a.v.i.d T.i.k.t.i.n
    t.i.k.t.i.n [at] a.d.v.a.n.c.e.d.r.e.l.a.y [dot] c.o.m
     
    David Tiktin, Mar 3, 2008
    #14
  15. On Sun, 02 Mar 2008 23:48:33 -0800, ymuntyan wrote:
    > On Mar 3, 12:19 am, Harald van Dijk <> wrote:
    >> On Sun, 02 Mar 2008 19:45:29 -0800, Peter Nilsson wrote:
    >> > Harald van Dijk <> wrote:
    >> >> ... [the] example prints the representation of a function pointer,
    >> >> not its value.

    >>
    >> > It's value is determined by the representation.

    >>
    >> Of course, but that's true for all types. Should we start printing 1.01
    >> as a series of bytes too, then?

    >
    > Isn't it what "binary file formats" is about?


    I meant printing the series of bytes as hexadecimal numbers, which is not
    what binary file formats are about.

    >> >> If multiple function pointer representations exist for one value,
    >> >> there is no portable way to print the value in such a way that the
    >> >> different representations become indistinguishable.

    >>
    >> > How is this any different to the case for %p? The only thing you're
    >> > guaranteed is that if you read via %p you'll get a pointer that
    >> > compares equal to the original.

    >>
    >> If you print the same value to printf twice, you can be sure you get
    >> the same string twice. If you print the representation of two identical
    >> values twice, you can't be sure you get the same string twice.

    >
    > You can not be sure that you'll get two identical strings from
    > printf("%p\n%p\n", p, p).


    The standard states that "the value of the pointer is converted to a
    sequence of printing characters, in an implementation-defined manner."
    This, by my reading, does not allow anything other than the value of the
    pointer to have an effect on the output. In particular, it does not allow
    the representation of the pointer (when multiple representations of the
    same value exist) to have an effect.
     
    Harald van Dijk, Mar 3, 2008
    #15
  16. David Tiktin said:

    > On 02 Mar 2008, Richard Heathfield <> wrote:
    >

    <snip>
    >>
    >> Well, no pointer value can be printed portably, since the output
    >> associated with %p is implementation-defined.

    >
    > I'm a little unclear on the point you're making here. I would have
    > said that the code:
    >
    > #include <stdio.h>
    > #include <limits.h>
    >
    > int main(void)
    > {
    > printf("%d\n", INT_MAX);
    >
    > return 0;
    > }
    >
    > is a completely portable way to print the value of INT_MAX even
    > though what's printed is obviously implementation defined.


    Right - the technique is portable, but the value isn't. :)

    <snip>

    > Can't you write to a
    > text file portably in C even though the result is implementation
    > defined?


    Again, the technique is portable, but the value isn't. Consider:

    #include <stdio.h>

    int main(void)
    {
    FILE *fp = fopen("foo.txt", "w");
    if(fp != NULL)
    {
    if(fputs("A\n", fp) != EOF && fclose(fp))
    {
    puts("All is well.");
    }
    }
    return 0; /* if fputs failed, the stream will be closed on exit! */
    }

    If "All is well" is displayed (under any conforming hosted implementation),
    we have created a text file, which in C terms contains one line comprising
    'A' and a newline character. So the technique is portable.

    But what have we actually created, in what we might call absolute terms? On
    a PC under Windows, the file will contain three bytes, with values 65, 13,
    and 10 (obviously I'm using decimal representation here). On an old-style
    Mac, it would contain just two bytes: 65, 13. On a Linux box (or, I
    *think*, a modern Mac), it would contain 65, 10. On an IBM mainframe,
    well, don't ask(!), but to start off with, that 'A' would be 193 rather
    than 65. The point is that, whilst the output can be interpreted
    consistently within the machine/OS/implementation combination, moving that
    file to another (disparate) system will (or at least may) result in that
    interpretation becoming invalidated unless some kind of data massage is
    performed.

    So I guess it all depends on what we mean by "portable"!

    --
    Richard Heathfield <http://www.cpax.org.uk>
    Email: -http://www. +rjh@
    Google users: <http://www.cpax.org.uk/prg/writings/googly.php>
    "Usenet is a strange place" - dmr 29 July 1999
     
    Richard Heathfield, Mar 3, 2008
    #16
  17. On Sun, 02 Mar 2008 19:59:19 +0200, Ioannis Vranos
    <> wrote:

    >I recall from previous discussions here, that we must cast a non-void
    >pointer to void * before printing its value with printf("%p"). Is it
    >true, and if yes why?


    Different types of object pointers are allowed to have different sizes
    and different representations. But you are allowed to convert
    (explicitly or implicitly) between any of these types and void* with
    no loss of information.

    scanf must accept many different kinds of pointers. %s requires a
    char*, %d requires an int*, etc. Therefore, it is not possible to
    have a rule that says any pointer in the variadic portion of the
    argument list would be "promoted" to void*. (There is such a rule
    that says short and char are promoted to int and float is promoted to
    double in the variadic portion of an argument list.) [scanf could
    have been designed to accept void pointers across the board but then
    compilers could not optionally check the arguments against the
    conversion specifications.]

    Rather than provide printf with a slew of conversion specifications
    (which could have also allowed function pointers to be printed), %p is
    used for all object pointers after they have been converted to void*.
    Since there is no automatic conversion to void* (for the variadic
    portion of an argument list), you must direct the compiler to perform
    the conversion by casting the value.


    Remove del for email
     
    Barry Schwarz, Mar 4, 2008
    #17
  18. Barry Schwarz <> wrote:
    > ...
    > scanf must accept many different kinds of pointers.
    > %s requires a char*, %d requires an [int], etc.


    True.

    > Therefore, it is not possible to have a rule that says
    > any pointer in the variadic portion of the argument
    > list would be "promoted" to void*.


    Why not?

    [Not that I'd want to see such a rule.]

    --
    Peter
     
    Peter Nilsson, Mar 4, 2008
    #18
  19. Ioannis Vranos

    CBFalconer Guest

    Peter Nilsson wrote:
    > Barry Schwarz <> wrote:
    >> ...
    >> scanf must accept many different kinds of pointers.
    >> %s requires a char*, %d requires an [int], etc.

    >
    > True.
    >
    >> Therefore, it is not possible to have a rule that says
    >> any pointer in the variadic portion of the argument
    >> list would be "promoted" to void*.

    >
    > Why not?


    They SHOULD be promoted to void. The type required is spelled out
    by the format string, so they can always be converted back to the
    appropriate form. This is one reason why the format string has to
    agree with the types received. All scanf needs to know is in the
    format, and in the void* pointer.

    --
    [mail]: Chuck F (cbfalconer at maineline dot net)
    [page]: <http://cbfalconer.home.att.net>
    Try the download section.



    --
    Posted via a free Usenet account from http://www.teranews.com
     
    CBFalconer, Mar 4, 2008
    #19
  20. On Mon, 3 Mar 2008 18:13:09 -0800 (PST), Peter Nilsson
    <> wrote:

    >Barry Schwarz <> wrote:
    >> ...
    >> scanf must accept many different kinds of pointers.
    >> %s requires a char*, %d requires an [int], etc.


    Interesting that your reader didn't quote what I wrote.

    >
    >True.
    >
    >> Therefore, it is not possible to have a rule that says
    >> any pointer in the variadic portion of the argument
    >> list would be "promoted" to void*.

    >
    >Why not?


    Because then scanf would not be receiving the expected type. Changing
    scanf so this could be done was mentioned two sentences later.

    >
    >[Not that I'd want to see such a rule.]



    Remove del for email
     
    Barry Schwarz, Mar 4, 2008
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ollej Reemt
    Replies:
    7
    Views:
    580
    Jack Klein
    Apr 22, 2005
  2. whatluo

    (void) printf vs printf

    whatluo, May 26, 2005, in forum: C Programming
    Replies:
    29
    Views:
    1,303
  3. Replies:
    5
    Views:
    863
    S.Tobias
    Jul 22, 2005
  4. Replies:
    1
    Views:
    428
    Victor Bazarov
    May 23, 2007
  5. guru
    Replies:
    8
    Views:
    296
Loading...

Share This Page