none
请教VC++中关于字节对齐的问题 RRS feed

  • 问题

  • 我想从文件中读取一段数据到一个结构体数组中
    struct RGB
    {
        BYTE R;
        BYTE G;
        BYTE B;
    }

    RGB* rgb=new RGB[100];
    myfile.read((char*)rgb,sizeof(GRG)*100);

    请问一下大家这样读取能正确读出数据吗?文件中的数据是这样排的:RGBRGBRGB...
    能不能正确的将100组RGB存放到这个数组里呢?
    2010年2月28日 3:49

答案

  • 你好,Windows在内存分配的时候rgb这个内存的数据段是连续的,就是说他没有对齐的问题。对齐的问题并不是这种情况下产生的。
    你用RGB* rgb=new RGB[100];这句话的效果和RGB* rgb = (RGB*)(new char[sizeof(RGB) * 100]);的效果其实是一样的。

    我在Win7下已通过测试支持上述说法。


    0xBAADF00D
    • 已标记为答案 谐音 2010年3月1日 5:11
    2010年2月28日 16:26
    版主
  • 这个……

    我觉得楼主,你可能有点儿晕。

    这个事情是这样的, 编译器为了提高CPU处理数据的速度,是会对数据做字节补齐的,sizeof() 的数据有可能大于实际字节数。请注意,这里说的CPU处理的数据,那是在内存中的。与在磁盘文件中的还是不同的。下面说你的这个问题:

    我感觉你的意思是怕执行 myfile.read((char*)rgb,sizeof(GRG)*100); 时,数据被填错了位置,导致错位,以至于这100个数据,不能正确从文件中还原。 在MS C++ 编译器中,规定:

    1) 规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数
    2) 结构体的字节对齐数为该结构中占用最大空间的类型所占用的字节数的倍数

    你的结构体3个成员类型一样,都是BYTE,该类型占用一个字节,因此你sizeof(RGB) 时会发现,值就是3! 因为3就是BYTE类型的倍数
    如果你的RGB 结构体再加上一个int s; 成员,那么sizeof(RGB) 的结果就是8 而不是7。 原因是,当前结构体内部的数据占字节最多的是int 类型(4个字节)。结构体实际字节数应为7,但7不是int类型所占字节数的倍数。因此需要填补一个字节,变成8. 这个空字节会补在结构体尾部。


    • 已标记为答案 谐音 2010年3月1日 5:11
    2010年3月1日 4:18
    版主

全部回复

  • 不一定,得看编译器的结构成员对齐方式。

    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful.
    Visual C++ MVP
    2010年2月28日 6:13
    版主
  • 你好,Windows在内存分配的时候rgb这个内存的数据段是连续的,就是说他没有对齐的问题。对齐的问题并不是这种情况下产生的。
    你用RGB* rgb=new RGB[100];这句话的效果和RGB* rgb = (RGB*)(new char[sizeof(RGB) * 100]);的效果其实是一样的。

    我在Win7下已通过测试支持上述说法。


    0xBAADF00D
    • 已标记为答案 谐音 2010年3月1日 5:11
    2010年2月28日 16:26
    版主
  • 你们好!就是说如果是按4个字节对齐的话,那么我这段代码就不正确的读出这些RGB数据付给变量了吧?只能一个字节一个字节的读了吧?
    2010年3月1日 3:49
  • 是的,如果是4字节对齐则不会得到正确的数据。
    麻烦把正确答案设为解答。
    2010年3月1日 3:58
    版主
  • 这个……

    我觉得楼主,你可能有点儿晕。

    这个事情是这样的, 编译器为了提高CPU处理数据的速度,是会对数据做字节补齐的,sizeof() 的数据有可能大于实际字节数。请注意,这里说的CPU处理的数据,那是在内存中的。与在磁盘文件中的还是不同的。下面说你的这个问题:

    我感觉你的意思是怕执行 myfile.read((char*)rgb,sizeof(GRG)*100); 时,数据被填错了位置,导致错位,以至于这100个数据,不能正确从文件中还原。 在MS C++ 编译器中,规定:

    1) 规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数
    2) 结构体的字节对齐数为该结构中占用最大空间的类型所占用的字节数的倍数

    你的结构体3个成员类型一样,都是BYTE,该类型占用一个字节,因此你sizeof(RGB) 时会发现,值就是3! 因为3就是BYTE类型的倍数
    如果你的RGB 结构体再加上一个int s; 成员,那么sizeof(RGB) 的结果就是8 而不是7。 原因是,当前结构体内部的数据占字节最多的是int 类型(4个字节)。结构体实际字节数应为7,但7不是int类型所占字节数的倍数。因此需要填补一个字节,变成8. 这个空字节会补在结构体尾部。


    • 已标记为答案 谐音 2010年3月1日 5:11
    2010年3月1日 4:18
    版主
  • 呵呵,的确有点儿晕了。。正是因为数据只在内存中对齐,而磁盘文件中不对齐,所以才发出如此疑问。因为我看到很多人读取文件中的一些信息的时候直接就用myfile.read((char*)s,sizeof(mystruct));如果这个结构体不是正好对齐的话,那么数据就不能被正确填充了。

    明白了,呵呵~谢谢大家了!

    2010年3月1日 5:11
  • 你好,我还想请教一下。我又遇到了一些疑问。结构体的字节对齐是按基本数据类型的吗?如果一个结构体中又有一个结构体成员,结果会是怎么样?如下:

    struct vertex

    {

    float x,y,z;

    };

    struct circular

    {

    vertex center;

    float radius;

    };

    我测试结果为:sizeof(vertex)=12;sizeof(circular)=16; 版主能不能解释下为什么不按vertex类型对齐?

    2010年4月25日 9:39
  • C++标准中没有规定结构体内存布局,编译器可以自由采取任何布局方式。不过一般的实现都假定对象在一块连续的内存上,所以把对象当位串数组读还是可以的。前提当然是你存盘的时候把对象也当位串数组存,这样有填充的内存块的话也会一起保存。

    结构的对齐是看最后一个成员的(假定前面的数据已经对齐),在用/Zp8编译的情况下__alignof(vertex)和__alignof(circular)都是4。



    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful.
    Visual C++ MVP
    2010年4月25日 19:42
    版主