0

I'm trying to create a complete uint32_t using vector of uint8_t bytes. It should be filled iteratively. It can happen in any of the following ways:

  • 1 byte and 3 bytes.
  • 2 bytes and 2 bytes.
  • 4 bytes.
  • 3 bytes and 1 byte.
    uint32_t L = 0;
    uint32_t* LPtr = &L;
    std::vector<uint8_t> data1 = {0x1f, 0x23};
    memcpy(LPtr, data1.data(), 2);
    EXPECT_EQ(0x231f, L);

Above works fine (first two bytes). But following is not (with the two sets of bytes).

    uint32_t L = 0;
    uint32_t* LPtr = &L;
    std::vector<uint8_t> data1 = {0x1f, 0x23};
    std::vector<uint8_t> data2 = {0x3a, 0xee};
    memcpy(LPtr, data1.data(), 2);
    memcpy(LPtr, data2.data(), 2);
    EXPECT_EQ(0x231f, L);
    EXPECT_EQ(0x231fee3a, L);

The issue I feel is LPtr does not point to the next byte that should be filled next. I tried LPtr+2 which is not pointing to individual byte of uint32_t.

This should be done using memcpy and output should go to uint32_t. Any idea to get this sorted?

Endianness is not an issue as of now. It can be corrected once the uint32_t is completed (when eventually 4 bytes get copied).

Any help is appreciated!

9
  • 2
    memcpy(reinterpret_cast<char *>(LPtr) + 2, data1.data(), 2); Commented Aug 13, 2022 at 17:40
  • 1
    The second call to memcpy overwrites the first data, because you pass the exact same destination pointer. Commented Aug 13, 2022 at 17:41
  • 3
    You may want using bit shifts instead of memcpy. Commented Aug 13, 2022 at 17:42
  • 1
    Have you looked up how your CPU stores data in memory? The bytes might not be in the order you expcect. en.wikipedia.org/wiki/Endianness Commented Aug 13, 2022 at 17:43
  • 1
    Instead of memcpy have a look at std::copy, it is a bit more type safe. And will in practice compile to assembly that is at least as good as memcpy. Commented Aug 13, 2022 at 18:04

1 Answer 1

2

The problem is you're using a pointer to uint32_t so incrementing it won't make it iterate by 1 byte, only by 4 bytes. Here is a version which populates all bytes of L, but it's still messing with endianness:

uint32_t gimmeInteger(std::vector<uint8_t> data1, std::vector<uint8_t> data2)
{
  assert((data1.size() == 2));
  assert((data2.size() == 2));
  uint32_t L = 0;
  uint8_t* LPtr = reinterpret_cast<uint8_t*>(&L);
  memcpy(LPtr, data1.data(), 2);
  memcpy(LPtr+2, data2.data(), 2);
  return L;
}
Sign up to request clarification or add additional context in comments.

1 Comment

One could mention that this is one of the few instances, where reinterpret_cast is used legally without aliasing trouble. (In general cases for unrelated types only possible for std::byte, char and unsigned char - uint8_t should be one of those - but e.g. not for signed char.) en.cppreference.com/w/cpp/language/reinterpret_cast

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.