代码之家  ›  专栏  ›  技术社区  ›  Ð..

这些结构的大小在文件中不同,但在程序内存中相同

  •  -2
  • Ð..  · 技术社区  · 6 年前

    考虑以下pod结构:

    struct MessageWithArray {
        uint32_t raw;
        uint32_t myArray[10];
    
        //MessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 } {  };
    };
    

    运行以下内容:

    #include <type_traits>
    #include <iostream>
    #include <fstream>
    #include <string>
    
    struct MessageWithArray {
        uint32_t raw;
        uint32_t myArray[10];
    
        //MessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 } {  };
    };
    
    //https://stackoverflow.com/questions/46108877/exact-definition-of-as-bytes-function
    template <class T>
    char* as_bytes(T& x) {
        return &reinterpret_cast<char&>(x);
        // or:
        // return reinterpret_cast<char*>(std::addressof(x));
    }
    
    int main() {
        MessageWithArray msg = { 0, {0,1,2,3,4,5,6,7,8,9} };
        std::cout << "Size of MessageWithArray struct: " << sizeof(msg) << std::endl;
        std::cout << "Is a POD? " << std::is_pod<MessageWithArray>() << std::endl;
        std::ofstream buffer("message.txt");
        buffer.write(as_bytes(msg), sizeof(msg));
        return 0;
    }
    

    给出以下输出:

    messagewitharray结构的大小:44

    是吊舱吗?一

    “message.txt”文件的十六进制转储如下:

    00  00  00  00  00  00  00  00  01  00  00  00  02  00  00  00
    03  00  00  00  04  00  00  00  05  00  00  00  06  00  00  00
    07  00  00  00  08  00  00  00  09  00  00  00
    

    现在,如果我取消对构造函数的注释(这样 MessageWithArray 具有零参数构造函数), 带数组的消息 成为非pod结构。然后我使用构造函数来初始化。这会导致代码发生以下更改:

    ....
    struct MessageWithArray {
        .....
    
        MessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 }{  };
    };
    ....
    int main(){
        MessageWithArray msg;
        ....
    }
    

    运行此代码,我得到:

    messagewitharray结构的大小:44

    是吊舱吗?零

    “message.txt”文件的十六进制转储如下:

    00  00  00  00  0D  0A  00  00  00  14  00  00  00  1E  00  00
    00  28  00  00  00  32  00  00  00  3C  00  00  00  46  00  00
    00  50  00  00  00  5A  00  00  00  64  00  00  00
    

    现在,我对实际的十六进制值不太感兴趣,我想知道的是 当sizeof()声明非pod结构转储与pod结构转储的字节数相同时,为什么非pod结构转储中还有一个字节 ?是否可能由于构造函数使结构成为非pod,所以已向结构添加了隐藏的内容?sizeof()应该是一个精确的编译时检查,对吗?是否有可能避免使用sizeof()进行度量?

    规格 我在Visual Studio 2017版本7.7.5,微软Visual C++ 2017上运行在Windows 10机器上的一个空项目中。

    英特尔酷睿i7-4600M CPU 64位操作系统,基于x64的处理器

    编辑 :我决定初始化结构以避免未定义的行为,因为问题在初始化时仍然有效。将它初始化为不带10的值将保留我最初观察到的行为,因为数组从未包含任何10秒的数据(即使它是垃圾和随机的)。

    2 回复  |  直到 6 年前
        1
  •  8
  •   HolyBlackCat    6 年前

    这与太空舱无关。

    你的 ofstream 以文本模式(而不是二进制模式)打开。在Windows上,这意味着 \n 转换为 \r\n .

    在第二个案例中,刚好有一个 0x0A ( \n )结构中的字节, 0x0D 0x0A ( \rn )这就是为什么你会看到一个额外的字节。


    此外,在第一种情况下使用未初始化的变量会导致未定义的行为,也就是说,这种情况本身并没有表现出来。

        2
  •  0
  •   user7860670    6 年前

    另一个答案解释了将二进制数据写入以文本模式打开的流的问题,但是这个代码根本是错误的。不需要倾倒任何东西,检查这些结构尺寸并验证它们是否相等的正确方法是使用 static_assert :

    struct MessageWithArray {
        uint32_t raw;
        uint32_t myArray[10];
    };
    
    struct NonPodMessageWithArray {
        uint32_t raw;
        uint32_t myArray[10];
    
        NonPodMessageWithArray() : raw(0), myArray{ 10,20,30,40,50,60,70,80,90,100 } {}
    };
    
    static_assert(sizeof(MessageWithArray) == sizeof(NonPodMessageWithArray));
    

    online compiler