StackedCrooked
StackedCrooked

Reputation: 35515

Can I prevent breaking anti-aliasing rules using this technique?

If I recall correctly, it would be undefined behavior to write to FastKey::key and then read from FastKey::keyValue:

struct Key {
    std::array<uint8_t, 6> MACAddress;
    uint16_t EtherType;
};

union FastKey {
    Key key;
    uint64_t keyValue;
};

However, I have been told that if I add char array to the union then the UB is cleared:

union FastKey {
    Key key;
    uint64_t keyValue;
    char fixUB[sizeof(Key)];
};

Is this true?

Edit

As usual my understanding was wrong. With the new information I gathered, I think that I can get the key as a uint64_t value like this:

struct Key {
    std::array<uint8_t, 6> MACAddress;
    uint16_t EtherType;
};

union FastKey {
    Key key;
    unsigned char data[sizeof(Key)];
};

inline uint64_t GetKeyValue(FastKey fastKey)
{
    uint64_t key = 0;
    key |= size_t(fastKey.data[0]) << 56;
    key |= size_t(fastKey.data[1]) << 48;
    key |= size_t(fastKey.data[2]) << 40;
    key |= size_t(fastKey.data[3]) << 32;
    key |= size_t(fastKey.data[4]) << 24;
    key |= size_t(fastKey.data[5]) << 16;
    key |= size_t(fastKey.data[6]) << 8;
    key |= size_t(fastKey.data[7]) << 0;
    return key;
}

I suspect that this will be equally fast as the original version. Feel free to correct me.

Update

@Steve Jessop I implemented a quick benchmark to test the performance of memcpy vs my solution. I'm not a benchmarking expert, so there may be stupid errors in the code the lead to wrong results. However, if the code is right then it would seem that memcpy is much slower.

Note: It seems the benchmark is wrong because the time to calculate the time for fast key is always zero. I'll see if I can fix it.

Upvotes: 2

Views: 189

Answers (1)

R. Martinho Fernandes
R. Martinho Fernandes

Reputation: 234634

No, reading a uint64_t if you have a Key object there is still UB. What isn't UB is to read a char, because there's an exception for char in the aliasing rules. Adding the array doesn't propagate the exception to the other types.

The version in the edit seems fine (though I'd use unsigned char), but now it is more complex than just using a reinterpret_cast from Key* to unsigned char* or a memcpy.

Upvotes: 4

Related Questions