Passing intptr_t to a function with void * prototype.

Discussion in 'C Programming' started by Jeroen Schot, Oct 4, 2010.

  1. Jeroen Schot

    Jeroen Schot Guest

    Hello,

    In a recent thread[1] on StackOverflow there was the question of passing
    an int where void * was expected. Of course this is not well defined.
    But what surprised me is that people remarked that passing an intptr_t
    might not work either.

    Given this example:

    #include <stdint.h>

    int foo(void *p)
    {
    intptr_t i = p;
    ...
    }

    ...
    intptr_t n = 5;
    foo(n);
    ...

    Is it true that i might not be equal to n because the standard only
    specifies the conversion (void *) -> (intptr_t) -> (void *) and not
    (intptr_t) -> (void *) -> (intptr_t)? If so, why?

    [1]: http://stackoverflow.com/q/3811171/251122

    Regards,
    --
    Jeroen Schot
     
    Jeroen Schot, Oct 4, 2010
    #1
    1. Advertising

  2. Jeroen Schot <> writes:

    > In a recent thread[1] on StackOverflow there was the question of passing
    > an int where void * was expected. Of course this is not well defined.
    > But what surprised me is that people remarked that passing an intptr_t
    > might not work either.
    >
    > Given this example:
    >
    > #include <stdint.h>
    >
    > int foo(void *p)
    > {
    > intptr_t i = p;
    > ...
    > }
    >
    > ...
    > intptr_t n = 5;
    > foo(n);
    > ...
    >
    > Is it true that i might not be equal to n because the standard only
    > specifies the conversion (void *) -> (intptr_t) -> (void *) and not
    > (intptr_t) -> (void *) -> (intptr_t)? If so, why?


    Yes, it's true.

    Imagine a machine were all pointers have two unused zero bits at "the
    bottom". The fastest way to convert a pointer to an intptr_t or back is
    simply to copy the bits, but that means that the bit pattern for 5 is
    not a valid pointer and if the hardware has pointer registers that
    simply ignore the bottom bits, passing a value like 5 might well not
    preserve it. The standard want to permit this sort of fast conversion.

    There are lots of other scenarios: imagine the more likely case of a
    machine with, say, 24 bit pointer registers and only 32 bit ints
    available for intptr_t. There will be intptr_t values that can't be
    converted (in all situations) to a pointer and back without loss of
    information. The plain casts

    intptr_t big_val = 0x1000000;
    intptr_t other = (intptr_t)(void *)big_val;

    might work, but the standard wants to permit the implementation free use
    of the hardware and so the conversion is not guaranteed to work in all
    cases.

    <snip>
    --
    Ben.
     
    Ben Bacarisse, Oct 4, 2010
    #2
    1. Advertising

  3. Jeroen Schot

    Eric Sosman Guest

    On 10/4/2010 5:01 AM, Jeroen Schot wrote:
    > Hello,
    >
    > In a recent thread[1] on StackOverflow there was the question of passing
    > an int where void * was expected. Of course this is not well defined.
    > But what surprised me is that people remarked that passing an intptr_t
    > might not work either.
    >
    > Given this example:
    >
    > #include<stdint.h>
    >
    > int foo(void *p)
    > {
    > intptr_t i = p;
    > ...
    > }
    >
    > ...
    > intptr_t n = 5;
    > foo(n);


    A diagnostic is required here, because the argument type does
    not match the parameter type and is not "silently convertible" to
    it. `foo( (void*)n )' would stand a better chance.

    > ...
    >
    > Is it true that i might not be equal to n because the standard only
    > specifies the conversion (void *) -> (intptr_t) -> (void *) and not
    > (intptr_t) -> (void *) -> (intptr_t)? If so, why?


    If intptr_t exists, any valid or null data pointer can be converted
    to intptr_t and back. However, the converted integer values might not
    cover the entire possible range of intptr_t values; there could be
    valid intptr_t's that do not convert to valid pointers.

    For example, imagine a system where void* and intptr_t both occupy
    64 bits, but void* really only spans a 48-bit address space, with the
    other 16 bits as "must be zero." If you set some of those bits in the
    intptr_t, they may get wiped out in conversion to void*, and then show
    up as zeroes upon the conversion back again.

    --
    Eric Sosman
    lid
     
    Eric Sosman, Oct 4, 2010
    #3
  4. Jeroen Schot

    Jeroen Schot Guest

    On 2010-10-04, Eric Sosman <> wrote:
    > On 10/4/2010 5:01 AM, Jeroen Schot wrote:
    >> [...]
    >> Given this example:
    >>
    >> #include<stdint.h>
    >>
    >> int foo(void *p)
    >> {
    >> intptr_t i = p;
    >> ...
    >> }
    >>
    >> ...
    >> intptr_t n = 5;
    >> foo(n);

    >
    > A diagnostic is required here, because the argument type does
    > not match the parameter type and is not "silently convertible" to
    > it. `foo( (void*)n )' would stand a better chance.


    Yes, I almost wrote this as an additional question. My compiler did warn
    about this, but with GCC it is not always obvious whether a warning is a
    required diagnostic or a 'helpful' reminder.

    > [...]
    > For example, imagine a system where void* and intptr_t both occupy
    > 64 bits, but void* really only spans a 48-bit address space, with the
    > other 16 bits as "must be zero." If you set some of those bits in the
    > intptr_t, they may get wiped out in conversion to void*, and then show
    > up as zeroes upon the conversion back again.


    This confirms my suspicions and gives a clear example of when/why this
    fails. Thank you (and Ben) for your answers.

    Regards,
    --
    Jeroen Schot
     
    Jeroen Schot, Oct 6, 2010
    #4
  5. Jeroen Schot wrote:
    > On 2010-10-04, Eric Sosman <> wrote:
    >> On 10/4/2010 5:01 AM, Jeroen Schot wrote:
    >>> [...]
    >>> ...
    >>> intptr_t n = 5;
    >>> foo(n);

    >>
    >> A diagnostic is required here, because the argument type does
    >> not match the parameter type and is not "silently convertible" to
    >> it. `foo( (void*)n )' would stand a better chance.

    >
    > Yes, I almost wrote this as an additional question. My compiler did warn
    > about this, but with GCC it is not always obvious whether a warning is a
    > required diagnostic or a 'helpful' reminder.


    You might try the -pedantic-errors option.
    --
    Marcin Grzegorczyk
     
    Marcin Grzegorczyk, Oct 6, 2010
    #5
    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:
    538
    Jack Klein
    Apr 22, 2005
  2. Stig Brautaset

    `void **' revisited: void *pop(void **root)

    Stig Brautaset, Oct 25, 2003, in forum: C Programming
    Replies:
    15
    Views:
    791
    The Real OS/2 Guy
    Oct 28, 2003
  3. Replies:
    5
    Views:
    841
    S.Tobias
    Jul 22, 2005
  4. intptr_t standard?

    , Aug 7, 2006, in forum: C Programming
    Replies:
    2
    Views:
    5,319
    Keith Thompson
    Aug 7, 2006
  5. Replies:
    1
    Views:
    412
    Victor Bazarov
    May 23, 2007
Loading...

Share This Page