ZachB ZachB - 2 months ago 14
C++ Question

Strict aliasing char* to a wider type without undefined behavior

I'm confused about whether or not this is a strict aliasing violation or invokes undefined behavior. Multiple people have told me it's not a violation and that there is no UB, but from reading the C++ spec it sounds like doing anything that dereferences a type-casted pointer (unless it was just cv-casted or casted to a compatible type or char) is UB.

#define SWAP(x) (((x) << 8) | ((x) >> 8)))

char* foo(char* data, size_t len16) {
int align = reinterpret_cast<uintptr_t>(data) % sizeof(uint16_t);
if (align == 0) {
uint16_t* data16 = reinterpret_cast<uint16_t*>(data);
for (size_t i = 0; i < len16; i++) {
data16[i] = SWAP(data16[i]);
}
} else {
throw "Unaligned";
}

return data;
}


https://godbolt.org/g/DIXtJX

(This is a slightly contrived example; in reality
SWAP
may be a third-party function that requires a
uint16_t
.)

Is the story changed because we've checked alignment, are confident about the size of the types and don't care about endianness? The remaining concern would, I guess, be dead code elimination by the optimizer.

If this is illegal, how would you efficiently interpret a
char
buffer (e.g. from a file) as its intended type (e.g.
int16
s)? I'm familiar with casting through a union, but I don't really see how that's any different (see casting through a union(1), aside from telling the compiler that it cannot do dead code elimination.

Answer

doing anything that dereferences a type-casted pointer (unless it was just cv-casted or casted to a compatible type or char) is UB.

That is not correct.

Any pointer can be cast to char* and void* and back. It is UB only when the original pointer is of a different type than the pointer type used when dereferencing the pointer. There are exceptions to even that. See Struct alignment and type reinterpretation for an example.

Comments