Of course doing the undefined thing works on almost any platform except DS9k, but that last formulation is quite elegant. It's a bit like byteswapping in that it's fairly simple to do but it's even simpler to not do by just never relying on the machine endianness.
Also shifts, especially variable-length shifts, are frequently slower than xor and add/sub (e.g., on x86, shl only works with cl and shlx has high latency), so that's another score for the xor variant.
> ... this explicitly relies on shifting something into the sign bit, which depending on the exact flavor of language standard you’re using is either not allowed or at best fairly recently ..
An unsigned has no sign bit, so the left shift just needs to be unsigned to make it "technically correct".
(Remember to not use smaller than int types though, due to integer promotion issues)
This is the perfect spot to use a bitfield. You can tell it signed or unsigned, and the compiler will deal with it all and optimize. No bit ops to get wrong or maintain. Very readable and scalable.
Of course doing the undefined thing works on almost any platform except DS9k, but that last formulation is quite elegant. It's a bit like byteswapping in that it's fairly simple to do but it's even simpler to not do by just never relying on the machine endianness.
Also shifts, especially variable-length shifts, are frequently slower than xor and add/sub (e.g., on x86, shl only works with cl and shlx has high latency), so that's another score for the xor variant.
> ... this explicitly relies on shifting something into the sign bit, which depending on the exact flavor of language standard you’re using is either not allowed or at best fairly recently ..
An unsigned has no sign bit, so the left shift just needs to be unsigned to make it "technically correct".
(Remember to not use smaller than int types though, due to integer promotion issues)
Yup. When you're twiddling bits you're better off using unsigned types in general anyway, and leaving converting to a signed type at the very end.
Eh the author's suggestions only seem better because C++ is insane.
The last one is definitely nice though!
Can you post examples in other languages where this would be easier?
This is the perfect spot to use a bitfield. You can tell it signed or unsigned, and the compiler will deal with it all and optimize. No bit ops to get wrong or maintain. Very readable and scalable.
At least GCC was very conservative in dealing with bitfields and, last time I bothered to check, generated suboptimal code.
Endianness of bit fields changes with arch. Ie. Is the first bit field member the most or least significant bit range of the associated word.
Not in C or C++, at least, the bit and byte order is not defined.
But the width and signedness of a bitfield are defined at compile-time, while in this example they need to come from a format read at runtime.
> the compiler
I love when people say this as if there's exactly one compiler with a fixed implementation for whatever opt pass.
That's not how this phrase is used. It usually encompasses any reasonably advanced compiler like clang, GCC, and sometimes MSVC.
But not including any of the slightly broken C compilers that the embedded hardware manufacturers provide (also, ICC neither)?
I'm just providing examples, not excluding everything unmentioned.
as of a few years ago, ICC is just LLVM with some tweaked settings