0

I have this memory that arrays of char are the only safely punnable types in C++ according to the standard. That is, if you have a char* pointer to the first element of an appropriately aligned and sized array of char, it's safe to reinterpret_cast<T*> that pointer, but would not be safe for e.g. uint8_t according to the standard.

However, I can't find this anywhere in the current draft standard. Am I misremembering? Did this change for C++17? Can somebody quote the relevant parts of the standard?

jacobsa
  • 5,719
  • 1
  • 28
  • 60

1 Answers1

2

It is a strict aliasing violation to use an expression of type T to read or write an array of char (if T is not one of the exceptions in the rule).

Strict aliasing isn't a two-way street: you can use a char expression to access a T, but not vice versa.

The section is [basic.lval]/10 in the C++14 standard. See here for the full text of it.

Further, the standard says that uint8_t is a typedef for another type. All known implementations make it a typedef for char or unsigned char.

Some people have recommended that the standard explicitly specify uint8_t be a character type. That would also solve problems like uint8_t x = 'a'; cout << x; not being well-defined.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Thanks, I think the exception for `char` in the strict aliasing rule ([draft standard link](http://eel.is/c++draft/basic#lval-8)) is what I was thinking of. – jacobsa Oct 19 '17 at 22:59
  • Though how does this interact with things like `std::aligned_storage`? Surely there's some standards-safe way to take an array of `char` and turn it into a `T*`? Or is this only through blessed types like `std::aligned_storage`? – jacobsa Oct 19 '17 at 23:00
  • @jacobsa you use placement-new to create objects in the aligned storage, or char array . Then the area is considered to be an object of the created type, and no longer an object of the aligned storage class etc. – M.M Oct 19 '17 at 23:04
  • Thanks. So let's say you use `mmap` to get a page from the OS as a `void*`, and want to treat it as a zeroed array of some struct type. What's the standards-compliant way to do this? Do you need to use placement new for each element of the array? Is the compiler likely to optimize this away for a POD struct? – jacobsa Oct 19 '17 at 23:08
  • @jacobsa You can placement-new the entire array and yes it ought to be a no-op. – n. m. could be an AI Oct 19 '17 at 23:28
  • The standard doesn't cover the process of objects being created outside of user C++ code . In practice it's likely to work as the compiler can't know that objects weren't correctly created – M.M Oct 19 '17 at 23:35