title: How to get around strict aliasing when casting uint8_t buffer bytes as another type?
body: <p>I want to define a struct to map the bytes of packets received over a serial stream. The number of payload bytes in the packet is variable, and there's a 16-bit CRC after the payload bytes. (The packet byte layout, with the CRC at the end, is legacy and can't change.) The whole point of the struct is for source code that uses such packets to find the named fields within the packet buffer without caring about the byte offsets of each part of the packet. And since the CRC's offset varies depending on the length of the payload data, I wrote a method for the struct that simply computes the appropriate address and returns a <code>uint16_t&amp;</code> to the 2-byte CRC, from which the source code that uses it can either read or write the CRC.</p>
  <p>Here's a simplified version of the packet struct I wrote, along with the <code>crc()</code> method:</p>
  <pre><code>#include &lt;stdint.h&gt;
  
  struct SPacket
  {
     uint8_t  startByte;  // always 0xEE
     uint8_t  identity;   // device identity byte
     uint8_t  ctrl_bits;
     uint8_t  seq_nbr;
     uint16_t length;     // length of data[] in bytes
     uint8_t  data[1];    // placeholder for 1 or more payload data bytes
     uint16_t &amp;crc();     // returns a reference to the packet's 16-bit CRC following the data
  };
  
  uint16_t &amp;SPacket::crc()
  {
     return *(uint16_t*)(data + length);
  }
  </code></pre>
  <p>But when I compile it with GCC, I get this error:</p>
  <pre><code>C:\Users\phonetagger&gt; g++ --version
  g++ (GCC) 4.8.1
  Copyright (C) 2013 Free Software Foundation, Inc.
  This is free software; see the source for copying conditions.  There is NO
  warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  
  C:\Users\phonetagger&gt; g++ -o test.o -c -O3 -Wall test.cpp
  C:\Users\phonetagger\test.cpp: In member function 'uint16_t&amp; SPacket::crc()':
  C:\Users\phonetagger\test.cpp:17:37: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
      return *(uint16_t*)(data + length);
                                       ^
  </code></pre>
  <p>BTW if I remove the -O3 or -Wall, the warning goes away, but I can't do that; my co-workers would scream at me. Is there any way to make GCC happy by altering my source code, and yet still have a member <code>crc()</code> method that returns a <code>uint16_t&amp;</code> to the 2-byte CRC following the packet's variable-length <code>data[]</code>?</p>
  <p>ALSO BTW... I know some of you are thinking my solution is broken on systems that can't handle unaligned accesses in hardware. I also know some of you are thinking my solution is broken on systems whose endianness doesn't match the byte order of the serial stream. Kudos to those of you who thought of that. My example is significantly simplified. In reality my struct uses user-defined type <code>ube16_t</code> (unsigned big-endian 16 bit type), but the same issue applies. I didn't want to complicate things by including the definition of type <code>ube16_t</code>.</p>