Endianness puzzle
Eric S. Raymond
esr at thyrsus.com
Mon Dec 12 18:55:19 UTC 2016
One of the nastiest things left in the codebase is the code around the
vint64 type, a workaround for pre-C99 toolchains in which the
existence of int64_t/uint64_t was not guaranteed.
Presently vint64 is a union. I've sealed off access to the members behind
macros, but for various good reasons I'd like to replace it with a
scalar 64-bit type (so that, for example, native comparison operations
can be used on it).
Here's a patch that works:
diff --git a/include/ntp_types.h b/include/ntp_types.h
index f769132..f42cfec 100644
--- a/include/ntp_types.h
+++ b/include/ntp_types.h
@@ -43,36 +43,36 @@
/*
* We now assume the platform supports a 64-bit scalar type (the ISC
- * library wouldn't compile otherwise). Sadly, getting rid of vint64
- * is not as simple as turning it into a scalar due to same strange
- * code in the calendar calculations.
+ * library wouldn't compile otherwise).
*/
-typedef union {
-# ifdef WORDS_BIGENDIAN
- struct {
- uint32_t hi; uint32_t lo;
- } h;
-# else
- struct {
- uint32_t lo; uint32_t hi;
- } h;
-# endif
-
- int64_t s; /* signed quad scalar */
- uint64_t u; /* unsigned quad scalar */
-} vint64; /* variant int 64 */
-
-/* hide the structure of a vint64 */
-#define vint64lo(n) (n).h.lo
-#define setvint64lo(n,v) (n).h.lo = (v)
-#define vint64hiu(n) (n).h.hi
-#define setvint64hiu(n,v) (n).h.hi = (v)
-#define vint64s(n) (n).s
-#define setvint64s(n,v) (n).s = (v)
-#define vint64u(n) (n).u
-#define setvint64u(n,v) (n).u = (v)
-#define negvint64(n) (n).s *= -1
+typedef uint64_t vint64;
+#define LAST32MASK 0x00000000ffffffffUL
+#define FIRST32MASK 0xffffffff00000000UL
+#define GET32LAST(n) ((n) & LAST32MASK)
+#define SET32LAST(n, v) (n) = (((n) & FIRST32MASK) | ((v) & LAST32MASK))
+#define GET32FIRST(n) ((n) >> 32)
+#define SET32FIRST(n,v) (n) = ((((v) & LAST32MASK) << 32) | ((n) & LAST32MASK))
+#ifdef WORDS_BIGENDIAN
+#define vint64lo(n) ((uint32_t)GET32FIRST(n))
+#define setvint64lo(n,v) SET32FIRST(n,v)
+#define vint64his(n) ((int32_t)(GET32LAST(n)))
+#define setvint64his(n,v) SET32LAST(n,v)
+#define vint64hiu(n) ((uint32_t)(GET32LAST(n)))
+#define setvint64hiu(n,v) SET32LAST(n,v)
+#else
+#define vint64lo(n) ((uint32_t)GET32LAST(n))
+#define setvint64lo(n,v) SET32LAST(n,v)
+#define vint64his(n) ((int32_t)(GET32FIRST(n)))
+#define setvint64his(n,v) SET32FIRST(n,v)
+#define vint64hiu(n) ((uint32_t)(GET32FIRST(n)))
+#define setvint64hiu(n,v) SET32FIRST(n,v)
+#endif
+#define vint64s(n) ((int64_t)(n))
+#define setvint64s(n,v) (n) = ((int64_t)(v))
+#define vint64u(n) (n)
+#define setvint64u(n,v) (n) = (v)
+#define negvint64(n) (n = ((uint64_t)((((int64_t)(n)) * -1))))
typedef uint16_t associd_t; /* association ID */
#define ASSOCID_MAX USHRT_MAX
My problem is that this *shouldn't* work. Unless ia64 became
big-endian while I wan't looking, it's backwards. The code
enabled by WORDS_BIGENDIAN is actually doing little-endian
extraction, and the code if WORDS_BIGENDIAN is not defined
is doing big-endian. Or so it seens to me.
Am I having an attack of teh stoopids here?
Consequences: if I can change vint54 to be a typedef of uint64_t I can
get rid of a bunch of grotty code.
--
<a href="http://www.catb.org/~esr/">Eric S. Raymond</a>
Morality is always the product of terror; its chains and
strait-waistcoats are fashioned by those who dare not trust others,
because they dare not trust themselves, to walk in liberty.
-- Aldous Huxley
More information about the devel
mailing list