title: reinterpret_cast between char* and std::uint8_t* - safe?
body: <p>Now we all sometimes have to work with binary data. In C++ we work with sequences of bytes, and since the beginning <code>char</code> was the our building block. Defined to have <code>sizeof</code> of 1, it is the byte. And all library I/O functions use <code>char</code> by default. All is good but there was always a little concern, a little oddity that bugged some people - the number of bits in a byte is implementation-defined.</p>
  
  <p>So in C99, it was decided to introduce several typedefs to let the developers easily express themselves, the fixed-width integer types. Optional, of course, since we never want to hurt portability. Among them, <code>uint8_t</code>, migrated into C++11 as <code>std::uint8_t</code>, a fixed width 8-bit unsigned integer type, was the perfect choice for people who really wanted to work with 8 bit bytes.</p>
  
  <p>And so, developers embraced the new tools and started building libraries that expressively state that they accept 8-bit byte sequences, as <code>std::uint8_t*</code>, <code>std::vector&lt;std::uint8_t&gt;</code> or otherwise.</p>
  
  <p>But, perhaps with a very deep thought, the standardization committee decided not to require implementation of <code>std::char_traits&lt;std::uint8_t&gt;</code> therefore prohibiting developers from easily and portably instantiating, say, <code>std::basic_fstream&lt;std::uint8_t&gt;</code> and easily reading <code>std::uint8_t</code>s as a binary data. Or maybe, some of us don't care about the number of bits in a byte and are happy with it.</p>
  
  <p>But unfortunately, two worlds collide and sometimes you have to take a data as <code>char*</code> and pass it to a library that expects <code>std::uint8_t*</code>. But wait, you say, isn't <code>char</code> variable bit and <code>std::uint8_t</code> is fixed to 8? Will it result into a loss of data? </p>
  
  <p>Well, there is an interesting Standardese on this. The <code>char</code> defined to hold exactly one byte and byte is the lowest addressable chunk of memory, so there can't be a type with bit width lesser than that of <code>char</code>. Next, it is defined to be able to hold UTF-8 code units. This gives us the minimum - 8 bits. So now we have a typedef which is required to be 8 bits wide and a type that is at least 8 bits wide. But are there alternatives? Yes, <code>unsigned char</code>. Remember that signedness of <code>char</code> is implementation-defined. Any other type? Thankfully, no. All other integral types have required ranges which fall outside of 8 bits.</p>
  
  <p>Finally, <code>std::uint8_t</code> is optional, that means that the library which uses this type will not compile if it's not defined. But what if it compiles? I can say with a great degree of confidence that this means that we are on a platform with 8 bit bytes and <code>CHAR_BIT == 8</code>.</p>
  
  <p>Once we have this knowledge, that we have 8-bit bytes, that <code>std::uint8_t</code> is implemented as either <code>char</code> or <code>unsigned char</code>, can we assume that we can do <code>reinterpret_cast</code> from <code>char*</code> to <code>std::uint8_t*</code> and vice versa? Is it portable?</p>
  
  <p>This is where my Standardese reading skills fail me. I read about safely derived pointers (<code>[basic.stc.dynamic.safety]</code>) and, as far as I understand, the following:</p>
  
  <pre><code>std::uint8_t* buffer = /* ... */ ;
  char* buffer2 = reinterpret_cast&lt;char*&gt;(buffer);
  std::uint8_t buffer3 = reinterpret_cast&lt;std::uint8_t*&gt;(buffer2);
  </code></pre>
  
  <p>is safe if we don't touch <code>buffer2</code>. Correct me if I'm wrong.</p>
  
  <p>So, given the following preconditions:</p>
  
  <ul>
  <li><code>CHAR_BIT == 8</code></li>
  <li><code>std::uint8_t</code> is defined.</li>
  </ul>
  
  <p>Is it portable and safe to cast <code>char*</code> and <code>std::uint8_t*</code> back and forth, assuming that we're working with binary data and the potential lack of sign of <code>char</code> doesn't matter?</p>
  
  <p>I would appreciate references to the Standard with explanations.</p>
  
  <p>EDIT: Thanks, Jerry Coffin. I'm going to add the quote from the Standard ([basic.lval], §3.10/10):</p>
  
  <blockquote>
    <p>If a program attempts to access the stored value of an object through a glvalue of other than one of the
    following types the behavior is undefined:</p>
    
    <p>...</p>
    
    <p>— a char or unsigned char type.</p>
  </blockquote>
  
  <p>EDIT2: Ok, going deeper. <code>std::uint8_t</code> is not guaranteed to be a typedef of <code>unsigned char</code>. It can be implemented as <em>extended unsigned integer type</em> and extended unsigned integer types are not included in §3.10/10. What now?</p>