代码之家  ›  专栏  ›  技术社区  ›  Nate

C++结构对齐与STL矢量

  •  7
  • Nate  · 技术社区  · 16 年前

    虽然我可以一个接一个地读,但这样做会很好:

    // I know in advance how many structs to read in
    vector<MyStruct> bunchOfStructs;
    bunchOfStructs.resize(numberOfStructs);
    
    ifstream ifs;
    ifs.open("file.dat");
    if (ifs) {
        ifs.read(&bunchOfStructs[0], sizeof(MyStruct) * numberOfStructs);
    }
    

    这是可行的,但我认为这只是因为数据结构大小恰好可以被编译器的结构对齐填充平均整除。我怀疑它会在另一个编译器或平台上崩溃。

    for 循环一次读取每个结构。

    问题是-->我什么时候需要关心数据对齐?向量中动态分配的内存是使用填充还是STL保证元素是连续的?

    5 回复  |  直到 16 年前
        1
  •  4
  •   Jerry Coffin    16 年前

    标准要求您能够创建结构类型的数组。执行此操作时,数组必须是连续的。这意味着,无论为struct分配什么大小,它都必须允许您创建一个数组。为了确保这一点,编译器可以分配额外的空间 在…内

    数据库中数据的空间 vector ::operator new (通过分配器类),以及 ●新操作员 需要分配适当对齐以存储任何类型的空间。

    您可以提供自己的分配器和/或重载 ●新操作员 --但是如果您这样做了,您的版本仍然需要满足相同的要求,因此在这方面不会有任何改变。

    换言之,只要文件中的数据是以与您试图读回数据基本相同的方式创建的,那么您需要的正是工作所需的。如果它是在另一台机器上创建的,或者是使用不同的编译器(甚至是使用不同标志的同一个编译器)创建的,那么您可能会遇到相当多的潜在问题--endianness、结构中的padding等方面的差异。

    结构 一次一个--您真的需要一次读取一个结构中的项,然后将每个项放入一个临时 struct ,最后加上填好的

    operator>> 使大部分工作自动化。它不会提高速度(例如),但可以保持代码更干净:

    struct whatever { 
        int x, y, z;
        char stuff[672-3*sizeof(int)];
    
        friend std::istream &operator>>(std::istream &is, whatever &w) { 
           is >> w.x >> w.y >> w.z;
           return is.read(w.stuff, sizeof(w.stuff);
        } 
    };
    
    int main(int argc, char **argv) { 
        std::vector<whatever> data;
    
        assert(argc>1);
    
        std::ifstream infile(argv[1]);
    
        std::copy(std::istream_iterator<whatever>(infile),
                  std::istream_iterator<whatever>(),
                  std::back_inserter(data));  
        return 0;
    }
    
        2
  •  2
  •   Brian R. Bondy    16 年前

    对于现有的文件,最好的办法是找出它的文件格式,并分别读入、读入和丢弃所有对齐字节。

    要将新数据保存到文件中,可以使用 boost serialization .

        3
  •  2
  •   Carl Norum    16 年前

    在您的例子中,每当对齐可能更改结构的布局时,都需要关注对齐。有两种方法可以使代码更易于移植。

    #pragma pack() . 在GCC中,您可以使用 __attribute__((__packed__)) .

    其次,可以向结构中添加显式填充。此选项允许您维护原始结构的性能属性,但会使结构的布局更加明确。例如:

    struct s {
        u_int8_t  field1;
        u_int8_t  pad0[3];
        u_int16_t field2;
        u_int8_t  pad1[2];
        u_int32_t field3;
    };
    
        4
  •  1
  •   Potatoswatter    16 年前

    endianness . STL保证存储在 vector

    至于对齐问题,谷歌 #pragma pack(1)

        5
  •  0
  •   user208608 user208608    16 年前

    如果您编写的OO代码需要了解类的内部工作原理,那么您就错了。你不应该假设任何关于类的内部工作方式;您应该只假设方法和属性在任何平台/编译器上的工作方式相同。

    您最好实现一个模拟向量功能的类(可能通过子类化向量)。作为一个“代理模式”实现,它可能只加载调用者访问过的那些结构。这将允许您同时处理任何endian问题。这种方式应该使它适用于任何平台或编译器。