何时可以将结构安全地散列为字节数组

When can a struct safely be hashed as an array of bytes?

本文关键字:字节 字节数 数组 结构 安全 何时可      更新时间:2023-10-16

对于相等意味着每个数据成员的相同大多数派生类型和字节相等的结构,如果有的话,什么时候可以安全地将结构散列为字节数组?

本文件

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3333.html

在标题"将对象散列为字节数组"下,表明带有任何填充的结构不能安全地作为字节数组进行散列。

是否需要对填充进行显式测试才能将结构安全地散列为字节数组?这足够吗?

如果是,下面的草图是否恰当地说明了该测试?

#include <cstddef>
#include <iostream>
struct A
{
    int i;
    float f;
    char c;
};
// hashing would start at offs_i (possibly hopping over a v-table) and end at
// offs_c + sizeof(char)
int main()
{
    const std::size_t size_A = sizeof(A);
    const std::size_t size_int = sizeof(int);
    const std::size_t size_float = sizeof(float);
    const std::size_t size_char = sizeof(char);
    const std::size_t offs_i = offsetof(A, i);
    const std::size_t offs_f = offsetof(A, f);
    const std::size_t offs_c = offsetof(A, c);
    bool padded = false;
    if (offs_f != size_int)
        padded = true;
    else if (offs_c != size_int + size_float)
        padded = true;
    std::cout << "padded? " << std::boolalpha << padded << std::endl;
}

如果一个结构确实有填充,是否有任何方法可以变通,允许将哈希作为字节数组,例如将填充位清零?

这里的"安全"是指两个比较相等的结构将散列为相同的值。

几乎从来没有。该标准没有定义继承是如何实现的,例如使用vtable指针,因此不能保证两个派生类型相同的类具有任何特定于实现的继承相关数据。

此外,由于它们不是POD,offsetof不能保证工作或产生有意义的结果——我相信它实际上只是一个普通的UB。

总之,不要把结构当作字节数组,因为它们不是

至于他在报纸上的意图,这更可能是对委员会中一些狂热的"er mah gerd表演!"狗的让步,而不是他想做的实际事情。

您之前引用的论文阐述了以下要求:

is_trivially_copyable<T>::value &&
is_standard_layout<T>::value &&
is_contiguous_layout<T>::value

对于结构本身和所有成员,必须递归地为true。

前两个检查已经是标准库的一部分,您可以自己实现is_contiguous_layout<T>::value。作为基础,将其成员的大小之和与结构本身的大小进行比较就足够了。我不认为,检查偏移量实际上是必要的。

如果您的类型仅由整数类型组成,那么这当然应该适用于"常用"平台(CHAR_BIT == 8,2-完成)。然而,我不确定它是否也适用于布尔值和浮点数,因为我相信该标准并没有要求在变量的值和它的位表示之间进行唯一的双向映射。

EDIT:我刚刚意识到,如果派生类中没有添加任何成员,或者比较碰巧具有相同成员的两个不同类,则不能保留条件of same most derived type。因此,您必须单独说明类型。

如果结构是POD,那么在初始化时,您应该能够为整个结构将bzero或memcpy设置为0,那么作为字节数组进行哈希应该是很好且高效的。