diff --git a/types.h b/types.h
index 62d30c9..29aa2b5 100644
--- a/types.h
+++ b/types.h
@@ -2,11 +2,13 @@
 #define TYPES_H
 
 #include "config.h"
+#include <stdint.h>
+#include <string.h>
 
-typedef unsigned char u8;
+typedef unsigned char  u8;
 typedef unsigned short u16;
-typedef signed short i16;
-typedef unsigned int u32;
+typedef signed short   i16;
+typedef unsigned int   u32;
 typedef unsigned long long int u64;
 
 /*
@@ -23,14 +25,42 @@ typedef unsigned long long int u64;
  * Per SMBIOS v2.8.0 and later, all structures assume a little-endian
  * ordering convention.
  */
+
 #if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN)
-#define WORD(x) (u16)((x)[0] + ((x)[1] << 8))
-#define DWORD(x) (u32)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24))
-#define QWORD(x) (((u64)DWORD((x) + 4) << 32) + DWORD(x))
-#else /* ALIGNMENT_WORKAROUND || BIGENDIAN */
-#define WORD(x) (u16)(*(const u16 *)(x))
-#define DWORD(x) (u32)(*(const u32 *)(x))
-#define QWORD(x) (u64)(*(const u64 *)(x))
+
+/* Safe portable fallback for big-endian or strict-alignment systems */
+#define WORD(x)  (u16)((x)[0] | ((x)[1] << 8))
+#define DWORD(x) (u32)((x)[0] | ((x)[1] << 8) | ((x)[2] << 16) | ((x)[3] << 24))
+#define QWORD(x) (((u64)DWORD((x) + 4) << 32) | DWORD(x))
+
+#else /* little-endian and unaligned access is OK */
+
+/* Use memcpy() to avoid alignment warnings and undefined behavior */
+static inline u16 get_u16(const void *p)
+{
+    u16 v;
+    memcpy(&v, p, sizeof(v));
+    return v;
+}
+
+static inline u32 get_u32(const void *p)
+{
+    u32 v;
+    memcpy(&v, p, sizeof(v));
+    return v;
+}
+
+static inline u64 get_u64(const void *p)
+{
+    u64 v;
+    memcpy(&v, p, sizeof(v));
+    return v;
+}
+
+#define WORD(x)  get_u16(x)
+#define DWORD(x) get_u32(x)
+#define QWORD(x) get_u64(x)
+
 #endif /* ALIGNMENT_WORKAROUND || BIGENDIAN */
 
-#endif
+#endif /* TYPES_H */

