Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Special Interest Groups
  3. C++ Gurus
  4. Puning... Back where I started with unions
Forum Updated to NodeBB v4.3 + New Features

Puning... Back where I started with unions

Scheduled Pinned Locked Moved Solved C++ Gurus
5 Posts 4 Posters 701 Views 2 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.
  • fcarneyF Offline
    fcarneyF Offline
    fcarney
    wrote on last edited by
    #1

    We use unions to convert between int32_t and float. This is done for some canbus code. I had read there are issues with this and researched it. I found that despite it being recommended against most modern C++ compilers support this. So I am really confused. The recommended way of using reinterpret_cast ends up working with raw pointers when converting to byte arrays. The memcpy way seems to be a bit cleaner, but you have to copy the data. I then did an experiment and I get zero warnings from clang or the compiler (I am sure if I turned something on it might complain) with default Qt settings for gcc. It seems to me the cleanest way to do this is still unions.

        {
            // puning
            qInfo() << "Puning:";
    
            using namespace std;
    
            union {
                int64_t i;
                int8_t b[8];
            } Pun;
    
            qInfo() << "union Puning:";
            Pun.i = 0x0102030405060708;
            string tmp;
            for_each(begin(Pun.b), end(Pun.b), [&](int8_t bv){
                tmp += to_string(bv) + " ";
            });
            qInfo() << tmp.data();
    
            qInfo() << "reinterpret_cast puning:";
            int64_t i = 0x0102030405060708;
            int64_t *pi = &i;
            int8_t* pb;
            pb = reinterpret_cast<int8_t*>(pi);
            tmp.clear();
            for_each(pb, pb+8, [&](int8_t bv){
                tmp += to_string(bv) + " ";
            });
            qInfo() << tmp.data();
    
            qInfo() << "memcpy puning:";
            int8_t ab[8];
            memcpy(ab, &i, sizeof(ab));
            tmp.clear();
            for_each(begin(ab), end(ab), [&](int8_t bv){
                tmp += to_string(bv) + " ";
            });
            qInfo() << tmp.data();
        }
    

    So I just am back where I started. As long as the compiler supports this gcc/mingw I am just not inclined to change. Yes, I read the lengthy discussions on SO and elsewhere. I just don't see why this cannot be part of standard C++. Are the compiler makers just rebelling against the standard? I have C++17 turned on BTW.

    C++ is a perfectly valid school of magic.

    kshegunovK aha_1980A 2 Replies Last reply
    0
    • fcarneyF fcarney

      We use unions to convert between int32_t and float. This is done for some canbus code. I had read there are issues with this and researched it. I found that despite it being recommended against most modern C++ compilers support this. So I am really confused. The recommended way of using reinterpret_cast ends up working with raw pointers when converting to byte arrays. The memcpy way seems to be a bit cleaner, but you have to copy the data. I then did an experiment and I get zero warnings from clang or the compiler (I am sure if I turned something on it might complain) with default Qt settings for gcc. It seems to me the cleanest way to do this is still unions.

          {
              // puning
              qInfo() << "Puning:";
      
              using namespace std;
      
              union {
                  int64_t i;
                  int8_t b[8];
              } Pun;
      
              qInfo() << "union Puning:";
              Pun.i = 0x0102030405060708;
              string tmp;
              for_each(begin(Pun.b), end(Pun.b), [&](int8_t bv){
                  tmp += to_string(bv) + " ";
              });
              qInfo() << tmp.data();
      
              qInfo() << "reinterpret_cast puning:";
              int64_t i = 0x0102030405060708;
              int64_t *pi = &i;
              int8_t* pb;
              pb = reinterpret_cast<int8_t*>(pi);
              tmp.clear();
              for_each(pb, pb+8, [&](int8_t bv){
                  tmp += to_string(bv) + " ";
              });
              qInfo() << tmp.data();
      
              qInfo() << "memcpy puning:";
              int8_t ab[8];
              memcpy(ab, &i, sizeof(ab));
              tmp.clear();
              for_each(begin(ab), end(ab), [&](int8_t bv){
                  tmp += to_string(bv) + " ";
              });
              qInfo() << tmp.data();
          }
      

      So I just am back where I started. As long as the compiler supports this gcc/mingw I am just not inclined to change. Yes, I read the lengthy discussions on SO and elsewhere. I just don't see why this cannot be part of standard C++. Are the compiler makers just rebelling against the standard? I have C++17 turned on BTW.

      kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by
      #2

      @fcarney said in Puning... Back where I started with unions:

      Yes, I read the lengthy discussions on SO and elsewhere. I just don't see why this cannot be part of standard C++.

      It simply isn't, it's stated as undefined behaviour (in C++11); however all the compilers I've worked with just comply with the C99 standard on that particular topic (which states it's valid to read and write different fields of a union).

      Read and abide by the Qt Code of Conduct

      1 Reply Last reply
      4
      • fcarneyF fcarney

        We use unions to convert between int32_t and float. This is done for some canbus code. I had read there are issues with this and researched it. I found that despite it being recommended against most modern C++ compilers support this. So I am really confused. The recommended way of using reinterpret_cast ends up working with raw pointers when converting to byte arrays. The memcpy way seems to be a bit cleaner, but you have to copy the data. I then did an experiment and I get zero warnings from clang or the compiler (I am sure if I turned something on it might complain) with default Qt settings for gcc. It seems to me the cleanest way to do this is still unions.

            {
                // puning
                qInfo() << "Puning:";
        
                using namespace std;
        
                union {
                    int64_t i;
                    int8_t b[8];
                } Pun;
        
                qInfo() << "union Puning:";
                Pun.i = 0x0102030405060708;
                string tmp;
                for_each(begin(Pun.b), end(Pun.b), [&](int8_t bv){
                    tmp += to_string(bv) + " ";
                });
                qInfo() << tmp.data();
        
                qInfo() << "reinterpret_cast puning:";
                int64_t i = 0x0102030405060708;
                int64_t *pi = &i;
                int8_t* pb;
                pb = reinterpret_cast<int8_t*>(pi);
                tmp.clear();
                for_each(pb, pb+8, [&](int8_t bv){
                    tmp += to_string(bv) + " ";
                });
                qInfo() << tmp.data();
        
                qInfo() << "memcpy puning:";
                int8_t ab[8];
                memcpy(ab, &i, sizeof(ab));
                tmp.clear();
                for_each(begin(ab), end(ab), [&](int8_t bv){
                    tmp += to_string(bv) + " ";
                });
                qInfo() << tmp.data();
            }
        

        So I just am back where I started. As long as the compiler supports this gcc/mingw I am just not inclined to change. Yes, I read the lengthy discussions on SO and elsewhere. I just don't see why this cannot be part of standard C++. Are the compiler makers just rebelling against the standard? I have C++17 turned on BTW.

        aha_1980A Offline
        aha_1980A Offline
        aha_1980
        Lifetime Qt Champion
        wrote on last edited by
        #3

        @fcarney just to mention the obvious: memcpy on uint32_t and probably uint64_t ist most likely only load and store instructions, so the overhead is minimal. Esp. on I/O bound data transfer like CAN bus.

        Btw., do you use QtCanBus for that?

        Regards

        Qt has to stay free or it will die.

        1 Reply Last reply
        1
        • fcarneyF Offline
          fcarneyF Offline
          fcarney
          wrote on last edited by
          #4

          I think we use some custom library for canbus. I am not sure where it is from. I was not involved in developing that piece.

          C++ is a perfectly valid school of magic.

          1 Reply Last reply
          0
          • Kent-DorfmanK Offline
            Kent-DorfmanK Offline
            Kent-Dorfman
            wrote on last edited by
            #5

            Old thread and I should know better than to chime in, but everyone is entitled to my opinion. Also, I had this very issue posed to me the other day in our embedded domain.

            If you are dealing with existing CAN devices that expect network transport of IEEE floating point numbers then you have to go with what is expected and my comments are moot. However, if you have control over the endpoints in your networking of devices then you should NOT transport floating point numbers as such across a network. AUTOSAR, MISRA, and JPL coding standards all recognize why this is a bad idea.

            Our engineer is designing a microcontroller based controller and he did the union/float thing to represent data being exchanged. I quickly got him on-board to use scaled integers instead, which are more the standard in the automotive CAN arena. There are some legacy devices that use fixed precision ASCII representations of floating point numbers, such as NMEA/GPS, so that is also an option where bandwidth is not a concern.

            Some points to consider regarding transport of native floating point numbers:

            • different or adhoc endian format of devices
            • devices that require native types to start on processor word sized boundaries
            • devices that emulated floating point operations (no FPU)

            Anyway, just something to think about.

            1 Reply Last reply
            1

            • Login

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