0
\$\begingroup\$

I am looking for an elegant alternative of the following code where wordXX contains always 16 bits:

uint64_t wordHi = 0xaa; // I would like u_int16_t over u_int64_t here
uint64_t wordMi = 0xbb; // because it represents the real data better
uint64_t wordLo = 0xcc;

uint64_t largeword = (wordHi << 32) + (wordMi << 16) + (wordLo << 0);

To me this (very simplified) code looks a bit dirty, because reader gets confused about the real size of the wordXX data.

I could store wordHi to largeword and then shift largeword and add wordMi and so on, but this would make the code worse and probably needs more CPU cycles.

Edit: changed u_int64_t to uint64_t in the example as suggested in the comments.

\$\endgroup\$
  • \$\begingroup\$ Please either post your real code or remove the "very simplified" disclaimer. \$\endgroup\$ – 200_success Mar 2 '16 at 22:34
  • 2
    \$\begingroup\$ The performance concerns of a handful of bit operations are almost certainly going to be negligible. Even if this is inside the tightest loop you can imagine, I highly doubt that you would see much of a performance hit over that, and I strongly doubt you could find a more readable and efficient method of doing that. \$\endgroup\$ – Dannnno Mar 2 '16 at 22:34
  • \$\begingroup\$ @200_success with simplified I want to express that the 16-bit integers are of course not constant values. So largeword = 0xaabbcc; would not help me a lot. \$\endgroup\$ – Jonas Stein Mar 2 '16 at 22:41
  • \$\begingroup\$ @Dannnno to me it looks strange to convert all 16-bit values to 64-bit, just to be able to shift them later. OK I could store wordMi to 32-bit and wordLo to 16-bit. But that makes it not much better... \$\endgroup\$ – Jonas Stein Mar 2 '16 at 22:45
  • \$\begingroup\$ Why are you using u_int64_t instead of the standard uint64_t? Why aren't you using u_int16_t for the words? \$\endgroup\$ – 200_success Mar 2 '16 at 22:46
2
\$\begingroup\$

Using uint16_t not a problem?

Your comment says you want to use uint16_t, so why don't you do that? It would make the code look like this:

uint16_t wordHi = 0xaa;
uint16_t wordMi = 0xbb;
uint16_t wordLo = 0xcc;

uint64_t largeword = ((uint64_t) wordHi << 32) + ((uint64_t) wordMi << 16) + wordLo;
\$\endgroup\$
5
\$\begingroup\$

Use a struct and a union to do what you want. Note that this implementation is verbose and can be combined into a single declaration. Also depending on your system architecture, you may need to pack the struct or declare the members in a different order.

typedef struct
{
  uint16_t Low;
  uint16_t Mid;
  uint16_t Hi;
  uint16_t Spare;
} Word64_t;

typedef union
{
  uint64_t Int64Val;
  Word64_t WordVal;
} Splitter_t;

Splitter_t splitter;
splitter.WordVal.Low = 0xaa;
splitter.WordVal.Mid = 0xbb;
splitter.WordVal.Hi = 0xcc;

printf("%x", splitter.Int64Val);  //should print 0xaabbcc
\$\endgroup\$
  • \$\begingroup\$ I think you would run into endianness issues with this solution. \$\endgroup\$ – JS1 Mar 3 '16 at 1:39
  • \$\begingroup\$ @JS1 That may be. It depends on the architecture, as I said. I do this all the time in embdeded. \$\endgroup\$ – Zack Mar 3 '16 at 3:15
  • \$\begingroup\$ If you can check the endianness of your architecture in a #define, you could define the order of elements in the struct differently based on the value of the #define. \$\endgroup\$ – user1118321 Mar 3 '16 at 3:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.