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 {
-	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))
+#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)
+#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)
+#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 */

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