reinterpret_cast unsigned char * as uint64_t * - 这是UB吗?

时间:2018-01-22 08:32:16

标签: c++ undefined-behavior

假设我们采用了一大堆unsigned char s。

std::array<uint8_t, 100500> blob;
// ... fill array ...

(注意:它已经对齐,问题不在于对齐。) 然后我们将其视为uint64_t[]并尝试访问它:

const auto ptr = reinterpret_cast<const uint64_t*>(blob.data());
std::cout << ptr[7] << std::endl;

投射到uint64_t然后阅读它看起来像我一样怀疑。

但是UBsan,-Wstrict-aliasing并没有触发它。 Google在FlatBuffers中使用了这种技术。 此外,Cap&#39; Proto使用此too

是不确定的行为?

2 个答案:

答案 0 :(得分:6)

您无法通过其他类型的glvalue访问unsigned char对象值。但相反的情况是授权的,您可以通过unsigned char glvalue [basic.lval]访问任何对象的值:

  

如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:[...]

     
      
  • charunsigned charstd​::​byte类型。
  •   

因此,为了100%符合标准,我们的想法是扭转reinterpret_cast

uint64_t i;
std::memcpy(&i, blob.data() + 7*sizeof(uint64_t), sizeof(uint64_t));
std::cout << i << std::endl;

它将产生完全相同的assembly

答案 1 :(得分:1)

转换本身定义明确(reinterpret_cast从不具有UB),但如果没有构造ptr[7]对象,则表达式“uint64_t”中左值转换的左值将为UB在那个地址。

由于未显示“// ... fill array ...”,因此可能在该地址中构造了一个uint64_t对象(假设您所说的地址具有足够的对齐):

const uint64_t* p = new (blob.data() + 7 * sizeof(uint64_t)) uint64_t();

如果在该地址中构造了uint64_t对象,那么所讨论的代码具有明确定义的行为。