假设我们采用了一大堆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。
是不确定的行为?
答案 0 :(得分:6)
您无法通过其他类型的glvalue访问unsigned char
对象值。但相反的情况是授权的,您可以通过unsigned char
glvalue [basic.lval]访问任何对象的值:
如果程序试图通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:[...]
char
,unsigned char
或std::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
对象,那么所讨论的代码具有明确定义的行为。