Casting from pointer types to non-pointer types

Discussion in 'C++' started by jois.de.vivre@gmail.com, Jun 6, 2007.

  1. Guest

    I am interfacing with a third party API (written in C, if that
    matters) that has an "event handler" function with the following
    definition:

    void event_handler(int event_code, unsigned long user_data);

    The function takes an event code along with the user data but does not
    act on or change the user data.
    In my application, I want to pass a pointer as the user data. This
    pointer is to an array allocated with new, say, as follows:

    char *array = new char[100];

    and passed to the event handler as follows:

    event_handler(1, reinterpret_cast<unsigned long>(array));

    My question is if it's safe to cast this to an unsigned long type if I
    want to reuse it later? Specifically will doing something like this
    cause me any trouble?

    void some_function(unsigned long pointer)
    {
    char *array = reinterpret_cast<char*>(pointer);
    /* do stuff with array */
    delete [] array;
    }

    On my machine both sizeof(char*) and sizeof(unsigned long) is 8 so
    while this is a pretty ugly solution, at first glance it would seem
    safe (at least from overflow).
    , Jun 6, 2007
    #1
    1. Advertising

  2. wrote:
    > I am interfacing with a third party API (written in C, if that
    > matters) that has an "event handler" function with the following
    > definition:
    >
    > void event_handler(int event_code, unsigned long user_data);
    >
    > The function takes an event code along with the user data but does not
    > act on or change the user data.
    > In my application, I want to pass a pointer as the user data. This
    > pointer is to an array allocated with new, say, as follows:
    >
    > char *array = new char[100];
    >
    > and passed to the event handler as follows:
    >
    > event_handler(1, reinterpret_cast<unsigned long>(array));
    >
    > My question is if it's safe to cast this to an unsigned long type if I
    > want to reuse it later? Specifically will doing something like this
    > cause me any trouble?


    It is safe and well-defined _if_ 'unsigned long' has the same size as
    the pointer to which you're casting it.

    >
    > void some_function(unsigned long pointer)
    > {
    > char *array = reinterpret_cast<char*>(pointer);
    > /* do stuff with array */
    > delete [] array;
    > }
    >
    > On my machine both sizeof(char*) and sizeof(unsigned long) is 8 so
    > while this is a pretty ugly solution, at first glance it would seem
    > safe (at least from overflow).


    It is.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Jun 6, 2007
    #2
    1. Advertising

  3. wrote:
    > I am interfacing with a third party API (written in C, if that
    > matters) that has an "event handler" function with the following
    > definition:
    >
    > void event_handler(int event_code, unsigned long user_data);
    >
    > The function takes an event code along with the user data but does not
    > act on or change the user data.
    > In my application, I want to pass a pointer as the user data. This
    > pointer is to an array allocated with new, say, as follows:
    >
    > char *array = new char[100];
    >
    > and passed to the event handler as follows:
    >
    > event_handler(1, reinterpret_cast<unsigned long>(array));
    >
    > My question is if it's safe to cast this to an unsigned long type if I
    > want to reuse it later? Specifically will doing something like this
    > cause me any trouble?
    >
    > void some_function(unsigned long pointer)
    > {
    > char *array = reinterpret_cast<char*>(pointer);
    > /* do stuff with array */
    > delete [] array;
    > }
    >
    > On my machine both sizeof(char*) and sizeof(unsigned long) is 8 so
    > while this is a pretty ugly solution, at first glance it would seem
    > safe (at least from overflow).


    I think it would be "generally unsafe", but if your unsigned longs
    really are 8 byte, then it will work. Still, an assert() that
    sizeof(unsigned long)==sizeof(char*) somewhere in your code
    won't hurt (and it will help others in 20 years' time track
    the bug as they port your code to machines using "__further",
    16-byte pointers :>).

    HTH,
    - J.
    Jacek Dziedzic, Jun 6, 2007
    #3
  4. Guest

    It should be safe. I believe in all current compiler, long and pointer
    have same size. Please google "LP64" for more information.
    , Jun 6, 2007
    #4
  5. Please quote some context. See my signature.

    wrote:
    > It should be safe. I believe in all current compiler, long and pointer
    > have same size. Please google "LP64" for more information.


    Not safe.
    On a 64bit Windows system, a pointer has 64bit, but long has 32bit like an int.

    --
    Thomas
    http://www.netmeister.org/news/learn2quote.html
    Thomas J. Gritzan, Jun 6, 2007
    #5
  6. wrote:
    > It should be safe. I believe in all current compiler, long and pointer
    > have same size. Please google "LP64" for more information.


    Win64 - BAM! - Pointers are 64 bit and longs are 32 bit.
    Victor Bazarov, Jun 6, 2007
    #6
  7. Guest

    On Jun 6, 12:13 pm, "Victor Bazarov" <> wrote:
    > wrote:
    > > I am interfacing with a third party API (written in C, if that
    > > matters) that has an "event handler" function with the following
    > > definition:

    >
    > > void event_handler(int event_code, unsigned long user_data);

    >
    > > The function takes an event code along with the user data but does not
    > > act on or change the user data.
    > > In my application, I want to pass a pointer as the user data. This
    > > pointer is to an array allocated with new, say, as follows:

    >
    > > char *array = new char[100];

    >
    > > and passed to the event handler as follows:

    >
    > > event_handler(1, reinterpret_cast<unsigned long>(array));

    >
    > > My question is if it's safe to cast this to an unsigned long type if I
    > > want to reuse it later? Specifically will doing something like this
    > > cause me any trouble?

    >
    > It is safe and well-defined _if_ 'unsigned long' has the same size as
    > the pointer to which you're casting it.
    >
    >
    >
    > > void some_function(unsigned long pointer)
    > > {
    > > char *array = reinterpret_cast<char*>(pointer);
    > > /* do stuff with array */
    > > delete [] array;
    > > }

    >
    > > On my machine both sizeof(char*) and sizeof(unsigned long) is 8 so
    > > while this is a pretty ugly solution, at first glance it would seem
    > > safe (at least from overflow).

    >
    > It is.
    >
    > V
    > --
    > Please remove capital 'A's when replying by e-mail
    > I do not respond to top-posted replies, please don't ask




    If the sizes differ, will the cast fail with a "loses precision"
    error, such as attempting to cast from a pointer to say, an int?

    char *array = new char[100];
    int ptr_val = reinterpret_cast<int>(array);

    on gcc:
    error: cast from 'char*' to 'int' loses precision

    not sure if this is true with all compilers ...
    , Jun 6, 2007
    #7
  8. wrote:
    > [..]
    > If the sizes differ, will the cast fail with a "loses precision"
    > error, such as attempting to cast from a pointer to say, an int?


    The Standard doesn't say what error message will be displayed. It
    is up to the implementation.

    > char *array = new char[100];
    > int ptr_val = reinterpret_cast<int>(array);
    >
    > on gcc:
    > error: cast from 'char*' to 'int' loses precision
    >
    > not sure if this is true with all compilers ...


    It is not.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Jun 6, 2007
    #8
  9. Jim Langston Guest

    <> wrote in message
    news:...
    >I am interfacing with a third party API (written in C, if that
    > matters) that has an "event handler" function with the following
    > definition:
    >
    > void event_handler(int event_code, unsigned long user_data);
    >
    > The function takes an event code along with the user data but does not
    > act on or change the user data.
    > In my application, I want to pass a pointer as the user data. This
    > pointer is to an array allocated with new, say, as follows:
    >
    > char *array = new char[100];
    >
    > and passed to the event handler as follows:
    >
    > event_handler(1, reinterpret_cast<unsigned long>(array));
    >
    > My question is if it's safe to cast this to an unsigned long type if I
    > want to reuse it later? Specifically will doing something like this
    > cause me any trouble?
    >
    > void some_function(unsigned long pointer)
    > {
    > char *array = reinterpret_cast<char*>(pointer);
    > /* do stuff with array */
    > delete [] array;
    > }
    >
    > On my machine both sizeof(char*) and sizeof(unsigned long) is 8 so
    > while this is a pretty ugly solution, at first glance it would seem
    > safe (at least from overflow).


    Are you sure you are doing what you think you are doing?

    array is a char pointer. It contains the address of the 100 characters that
    new allocated. Your reinterpret_cast<unsigned long>( array ) is
    reinterpreting this *pointer* to an integer. I suspect you actually wanted
    to use the buffer itself to hold the integer. Am I correct?

    This program for one run on my system outputs:
    4
    3288656

    Which is it you wanted to use? Notes follow the code.

    #include <iostream>

    void event_handler(int event_code, unsigned long user_data)
    {
    std::cout << user_data << "\n";
    }

    int main()
    {
    char *array = new char[100];

    array[0] = 4;
    array[1] = 0;
    array[2] = 0;
    array[3] = 0;
    array[4] = 0;
    array[5] = 0;
    array[6] = 0;
    array[7] = 0;

    event_handler(1, *reinterpret_cast<unsigned long*>( array ));
    event_handler(1, reinterpret_cast<unsigned long>( array ));

    return 0;
    }

    This can be dangerous on some systems (treating the contents of some other
    type as an integer) becasue of byte alignment. On some systems if an
    integer is not correctly byte aligned the program can run slower,
    malfunction or crash. Generally a integral type needs to be aligned on it's
    size. A 4 byte integer on a byte evenly divisible by 4. An 8 byte integer
    on a byte evenly divisible by 8, etc... So in that case, if you need to use
    the buffer itself as the integer, it may not be safe depending on your
    platform.

    Notice how I'm passing the *contents* of the buffer as an unsigned long. I
    cast the char pointer to an unsigned long pointer, then derefence it (asking
    for it's contents).
    Jim Langston, Jun 7, 2007
    #9
  10. James Kanze Guest

    On Jun 6, 10:28 pm, "Victor Bazarov" <> wrote:
    > wrote:
    > > [..]
    > > If the sizes differ, will the cast fail with a "loses precision"
    > > error, such as attempting to cast from a pointer to say, an int?


    > The Standard doesn't say what error message will be displayed. It
    > is up to the implementation.


    > > char *array = new char[100];
    > > int ptr_val = reinterpret_cast<int>(array);


    > > on gcc:
    > > error: cast from 'char*' to 'int' loses precision


    > > not sure if this is true with all compilers ...


    > It is not.


    Are you sure. According to the standard, "A pointer can be
    explicitly converted to any integral type large enough to hold
    it." (From the section on reinterpret_cast.) Converting a
    pointer to an integral type which is not large enough to hold it
    cannot be done using reinterpret_cast. A compiler is required
    to emit a diagnostic.

    According to the C++ standard, the same thing holds for a C
    style cast. In C, however, it is undefined behavior, and
    C compilers historically have supported it, so that I expect a
    lot of C++ compilers will accept it unless you request strict
    conformance. Both Sun CC and g++ give an error regardless of
    the type of cast, in default mode. Using a C-style cast in C
    provokes a warning from gcc, and nothing from Sun cc, however.
    This is a point where the two languages differ.

    The other direction is fine, however, and there is no problem
    using reinterpret_cast to convert a char to a pointer.

    In the case in question, the poster needed a round trip
    conversion pointer to integral type back to pointer. This
    obviously can only work if the integral type is large enough.
    Most of the time, however, it is the reverse that is needed; the
    de facto standard "user data" type is void*, and if all you need
    is a char... char->void*->char is forbidden by the standard, you
    have to use char->void*->intptr_t->char. (And if the system
    doesn't have an intptr_t, then you're out of luck.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jun 7, 2007
    #10
  11. James Kanze Guest

    On Jun 6, 8:24 pm, Jacek Dziedzic
    <> wrote:
    > wrote:
    > > I am interfacing with a third party API (written in C, if that
    > > matters) that has an "event handler" function with the following
    > > definition:


    > > void event_handler(int event_code, unsigned long user_data);


    > > The function takes an event code along with the user data
    > > but does not act on or change the user data. In my
    > > application, I want to pass a pointer as the user data.
    > > This pointer is to an array allocated with new, say, as
    > > follows:


    > > char *array = new char[100];


    > > and passed to the event handler as follows:


    > > event_handler(1, reinterpret_cast<unsigned long>(array));


    > > My question is if it's safe to cast this to an unsigned long
    > > type if I want to reuse it later? Specifically will doing
    > > something like this cause me any trouble?


    > > void some_function(unsigned long pointer)
    > > {
    > > char *array = reinterpret_cast<char*>(pointer);
    > > /* do stuff with array */
    > > delete [] array;
    > > }


    > > On my machine both sizeof(char*) and sizeof(unsigned long) is 8 so
    > > while this is a pretty ugly solution, at first glance it would seem
    > > safe (at least from overflow).


    > I think it would be "generally unsafe", but if your unsigned longs
    > really are 8 byte, then it will work. Still, an assert() that
    > sizeof(unsigned long)==sizeof(char*) somewhere in your code
    > won't hurt (and it will help others in 20 years' time track
    > the bug as they port your code to machines using "__further",
    > 16-byte pointers :>).


    If the integral type isn't long enough, the code shouldn't
    compile, at least according to the C++ standard (and the
    compilers I have at hand).

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jun 7, 2007
    #11
  12. James Kanze Guest

    On Jun 6, 8:39 pm, wrote:
    > It should be safe. I believe in all current compiler, long and pointer
    > have same size. Please google "LP64" for more information.


    It's certainly not required, and in the past, I've used
    compilers with 6 byte pointers and 4 byte longs. I've also
    heard rumors that some 64 bit Windows compilers have 32 bit
    longs---it seems stupid, but you never know. I would certainly
    never assume that an unsigned long is big enough to hold a
    pointer on all systems, or even that there is an integral type
    large enough to hold a pointer. (If I'm not mistaken, at the
    hardware level, pointers can be 80 bits on a 64 bit Intel or
    AMD, even though the largest integral type is only 64 bits.)

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Jun 7, 2007
    #12
    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. kevin
    Replies:
    11
    Views:
    5,798
    Andrew McDonagh
    Jan 8, 2005
  2. Jason Heyes
    Replies:
    2
    Views:
    588
    Jason Heyes
    Feb 14, 2005
  3. Replies:
    5
    Views:
    531
  4. Wally Barnes
    Replies:
    3
    Views:
    518
    Wally Barnes
    Nov 20, 2008
  5. Sosuke

    Up casting and down casting

    Sosuke, Dec 20, 2009, in forum: C++
    Replies:
    2
    Views:
    559
    James Kanze
    Dec 20, 2009
Loading...

Share This Page