Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QGraphicsItem* conversion into long using reinterpret_cast
Forum Updated to NodeBB v4.3 + New Features

QGraphicsItem* conversion into long using reinterpret_cast

Scheduled Pinned Locked Moved Unsolved General and Desktop
7 Posts 4 Posters 532 Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    tushu
    wrote on last edited by
    #1

    I am creating test cases for my code. For that, I am capturing my code ( functions ) in Capture Mode and in Run mode I am runnig that captured code. And if both are giving me same output, then my test case is pass otherwise it is fail.

    Capture code (which is already written ) does not accept non primitive data types.
    Means if some function has Non primitive data types as arguments, then it will not accept. So I need to write a capture function in such a way that it's argument will be primitive data types.

    So the functions which has non primitive data types as arguments, I am converting them into primitive data type and then after capturing, again converting into it's original type using reinterpret_cast.
    Let us say I have following function :

    SelectObject()
    {
      QGraphicsItem* currentSelectedItem = _scene->itemAt( some location );      
      long currentItem = reinterpret_cast<long>(currentSelectedItem);
      SelectObjectCapture(currentItem);
    }
    
    SelectObjectCapture(long currentSelectedItem)
    {
        CAPTURE FUNCTION(SelectObjectCapture,currentSelectedItem);
        QGraphicsItem* currentItem = reinterpret_cast<QGraphicsItem*>(currentSelectedItem);   
        
        // then using currentItem in code
    }
    

    But this currentItem is leading to crash in RUN MODE. It perfectly works fine in Capture mode or without any mode.
    Am I correct in reinterpret_cast ?

    1 Reply Last reply
    0
    • Chris KawaC Online
      Chris KawaC Online
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by Chris Kawa
      #2

      Am I correct in reinterpret_cast ?

      No, What you're doing is dangerous and depends on the platform, toolchain and OS.
      For example on 64bit Windows QGraphicsItem* is 8 bytes in size and long is 4 bytes, so you're truncating half of the value. Casting it back you're only recovering lower half of the pointer, which obviously is wrong.

      It might just so happen that your pointer has a value with non-zero bits only in the lower half of it and then it will accidentally work, but that's depending on your memory allocator and the OS, so nothing you should rely on.

      Also, purely from language standpoint, casting a pointer to an integer via reinterpret_cast is implementation defined, meaning you're relying entirely on your compiler vendor for what happens, and you're outside of the standard C++.

      I don't know what those modes you mentioned are, but when doing bit casting the least you have to do is make sure the types have the same size (and probably alignment too), otherwise you're just guessing. Prefer types that have defined sizes like uint64_t, instead of platform and toolset dependent like long, which will vary. Also a pointer is a pretty primitive type, so you should probably have support for it. If you insist on using integers to store pointers there's uintptr_t that is an integer of a size that can hold a pointer to void. I'll just mention that on some platforms pointers to different types can have different sizes too i.e. sizeof(char*) != sizeof(int*), so, although unlikely that it affects you, what you're doing is a risky business.

      JonBJ 1 Reply Last reply
      2
      • Paul ColbyP Offline
        Paul ColbyP Offline
        Paul Colby
        wrote on last edited by
        #3

        Hi @tushu, I'm not really sure, but there's a few things I can suggest here.

        First off, depending on the platform, long and pointers aren't necessarily the same size. At the very least, I would add something like:

        static_assert(sizeof(void *) == sizeof(long), "size not the same");
        

        Though I would expect a good compiler to already warn on one of the reinterpret_cast lines if the sizes didn't match.

        Next, I would suggest, instead of using long as your primitive type, try using either intptr_t or qintptr. Both should be guaranteed to be the right size I think.

        Finally, a type-safe might be to use a QHash or QMap to map your primitive to the pointer instead. Something like (pseudo-code only):

        QHash<int, QGraphicsItem*> capturedItems;
        
        SelectObject()
        {
          static int itemIndex = 0;
          capturedItems.insert(itemIndex, _scene->itemAt( some location ));
          SelectObjectCapture(itemIndex++);
        }
        
        SelectObjectCapture(long currentSelectedItem)
        {
            CAPTURE FUNCTION(SelectObjectCapture,currentSelectedItem);
            QGraphicsItem* currentItem = capturedItems.take(currentSelectedItem);
            
            // then using currentItem in code
        }
        

        But its also very possible that the "crash" is to do with the pointer's lifetime management, rather than the re-castings (ie the pointer might be the correct value, but the item it points to might have been destroyed already). I would strongly suggest logging to pointer values, then running in a debugger to see exactly where the crash happens (it won't be on the reinterpret_cast itself, but something soon after).

        Cheers.

        1 Reply Last reply
        2
        • Chris KawaC Chris Kawa

          Am I correct in reinterpret_cast ?

          No, What you're doing is dangerous and depends on the platform, toolchain and OS.
          For example on 64bit Windows QGraphicsItem* is 8 bytes in size and long is 4 bytes, so you're truncating half of the value. Casting it back you're only recovering lower half of the pointer, which obviously is wrong.

          It might just so happen that your pointer has a value with non-zero bits only in the lower half of it and then it will accidentally work, but that's depending on your memory allocator and the OS, so nothing you should rely on.

          Also, purely from language standpoint, casting a pointer to an integer via reinterpret_cast is implementation defined, meaning you're relying entirely on your compiler vendor for what happens, and you're outside of the standard C++.

          I don't know what those modes you mentioned are, but when doing bit casting the least you have to do is make sure the types have the same size (and probably alignment too), otherwise you're just guessing. Prefer types that have defined sizes like uint64_t, instead of platform and toolset dependent like long, which will vary. Also a pointer is a pretty primitive type, so you should probably have support for it. If you insist on using integers to store pointers there's uintptr_t that is an integer of a size that can hold a pointer to void. I'll just mention that on some platforms pointers to different types can have different sizes too i.e. sizeof(char*) != sizeof(int*), so, although unlikely that it affects you, what you're doing is a risky business.

          JonBJ Online
          JonBJ Online
          JonB
          wrote on last edited by
          #4

          @Chris-Kawa said in QGraphicsItem* conversion into long using reinterpret_cast:

          on some platforms pointers to different types can have different sizes too i.e. sizeof(char*) != sizeof(int*)

          OMG! Reference/example please? This obviously implies they can have different values, so a pointer to one cannot be exchanged with a pointer to the other. Which I would have thought was enough to break much code where you have to swap between these pointer types to do low-level functions. For example how would memcpy() work? How would malloc() return a pointer which can point to any type?

          Chris KawaC 1 Reply Last reply
          0
          • JonBJ JonB

            @Chris-Kawa said in QGraphicsItem* conversion into long using reinterpret_cast:

            on some platforms pointers to different types can have different sizes too i.e. sizeof(char*) != sizeof(int*)

            OMG! Reference/example please? This obviously implies they can have different values, so a pointer to one cannot be exchanged with a pointer to the other. Which I would have thought was enough to break much code where you have to swap between these pointer types to do low-level functions. For example how would memcpy() work? How would malloc() return a pointer which can point to any type?

            Chris KawaC Online
            Chris KawaC Online
            Chris Kawa
            Lifetime Qt Champion
            wrote on last edited by Chris Kawa
            #5

            @JonB said:

            OMG! Reference/example please?

            It's mostly the old stuff, especially the ones with segmented memory models. Some examples are listed here: comp.lang.c FAQ. Btw. there are also examples of null pointer not being 0 on some platforms. Using nullptr constant is important :)

            For example how would memcpy() work? How would malloc() return a pointer which can point to any type?

            These functions operate on void*, which has a specific size, so there's no problem. Now how would you use a pointer of different size with them? I don't know. I've never worked with any platform like that.

            JonBJ 1 Reply Last reply
            0
            • Chris KawaC Chris Kawa

              @JonB said:

              OMG! Reference/example please?

              It's mostly the old stuff, especially the ones with segmented memory models. Some examples are listed here: comp.lang.c FAQ. Btw. there are also examples of null pointer not being 0 on some platforms. Using nullptr constant is important :)

              For example how would memcpy() work? How would malloc() return a pointer which can point to any type?

              These functions operate on void*, which has a specific size, so there's no problem. Now how would you use a pointer of different size with them? I don't know. I've never worked with any platform like that.

              JonBJ Online
              JonBJ Online
              JonB
              wrote on last edited by JonB
              #6

              @Chris-Kawa said in QGraphicsItem* conversion into long using reinterpret_cast:

              These functions operate on void*

              They do indeed, but how do they actually get implemented? If you want to make e.g. a "simple" memcpy() at some point you have to cast that void * to a char * so you can access the bytes which are there, and then according to you we have a problem because they may not be the same size/convertible :) My question was purely out of interest.

              Chris KawaC 1 Reply Last reply
              0
              • JonBJ JonB

                @Chris-Kawa said in QGraphicsItem* conversion into long using reinterpret_cast:

                These functions operate on void*

                They do indeed, but how do they actually get implemented? If you want to make e.g. a "simple" memcpy() at some point you have to cast that void * to a char * so you can access the bytes which are there, and then according to you we have a problem because they may not be the same size/convertible :) My question was purely out of interest.

                Chris KawaC Online
                Chris KawaC Online
                Chris Kawa
                Lifetime Qt Champion
                wrote on last edited by
                #7

                @JonB I'm purely speculating but I'd imagine the compiler for that platform would have some dedicated "variants" of memcpy for these cases. Assuming of course that copying between these types even makes sense. They could just be unrelated. Or if one pointer is something like [segment, offset] and the other is just offset maybe there's some additional function that sets a "base segment" and then memcpy just works on offsets in that segment, i.e. the conversion to that void* would be lossy. A comment here seems to suggest that could be the case.

                Idk, there's probably a hefty manual for any such unusual platform on how to do these things. I often write code that needs to be portable across different PCs and game consoles and there are some quirky differences there, but not to that degree. It would be a fun challenge to write portable code for machines where even pointers differ :)

                1 Reply Last reply
                0

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved