user1079505
user1079505

Reputation: 172

Can I use union to convert between integers of various size?

Let's consider a union of integers of different sizes. Is it guaranteed that if a number fits the range of each of the integer types, it can be written to and read out from any of the union data members correctly?

E.g. this code

  union U {
    int32_t i;
    int16_t s;
  } u;
  u.s = 1000;
  std::cout<<u.i<<std::endl;

I verified that it prints correctly "1000" on one computer. Is it guaranteed to work the same on any other system? I guess on any system the endianness would be the same for any integer type, so it's rather a question whether the union is guaranteed to use the less significant bytes of the larger integer for the smaller one?

I know this has no chance to work for negative numbers, so let's consider non-negative numbers only.

Upvotes: 0

Views: 687

Answers (2)

phuclv
phuclv

Reputation: 41962

No, that only works in little endian. In big endian the bytes are stored from the most significant position down. 0xdeadbeef will be stored in memory as ef be ad de in little endian and de ad be ef big endian in memory so reading 2 bytes from the start address will result in 0xbeef and 0xdead in those machines respectively

However you're getting undefined behavior, because you're writing the smaller 2-byte field first then read the larger one. That means the high 2 bytes of int32_t will contain garbage. That's disregarding the fact that using union in C++ is already UB. You can only do that in C

If you write the larger field first the read the smaller one then it works even for signed types:

u.i = -1000;
std::cout << u.s << '\n';

This will print out as expected on a little endian machine

Upvotes: 2

thelizardking34
thelizardking34

Reputation: 348

The union will always be only as big as necessary to hold its largest data member.

The other data members are allocated in the same bytes as the largest member.

The details of how the 'other members' are allocated is implementation defined. By this definition, the answer is no it's not guaranteed. See: https://en.cppreference.com/w/cpp/language/union "Explanation"

Since C++14, all non-static data members of the union will have the same address; but that doesn't say anything about endianness or implementation support.

Upvotes: 1

Related Questions