【问题标题】:g++ 9.2.1 (Linux) causes seg fault but Codeblocks on windows does notg++ 9.2.1 (Linux) 导致段错误,但 Windows 上的代码块不会
【发布时间】:2020-01-13 14:18:12
【问题描述】:

以下简单代码(二进制文件处理)在与适用于 Windows 的 Codeblocks 17.12 (mingw32-g++) 捆绑的编译器上运行良好,但在适用于 Linux 的 g++ 9.2.1(在 Ubuntu 19.10 上)出现分段错误:

#include <iostream>
#include <fstream>
using namespace std;
class A {
public:
    int x;
    string y;
};
int main()
{
    ofstream k;
    A m;
    m.x = 10;
    m.y = "Hello";
    k.open("file.dat", ios::binary);
    k.write(reinterpret_cast<char *>(&m), sizeof(A));
    k.close();
    ifstream i;
    A t;
    i.open("file.dat", ios::binary);
    i.seekg(0, ios::beg);
    i.read(reinterpret_cast<char *>(&t), sizeof(A));
    cout << t.x << " " << t.y;
    i.close();
    return 0;
}

我是不是做错了什么,Windows 上最小的 g++ 可以原谅我,但 g++-Linux 不是?还是我发现了一个错误?

【问题讨论】:

  • 您的代码调用了未定义的行为。将对象所在的内存写入文件是正确的序列化。在线搜索该术语以获取更多信息。
  • 只有POD types没有指针,你才能读取或写入原始对象。 std::string 基本上是指向堆分配数据和字符串大小的指针(小字符串优化除外),因此您无法将原始 std::string 对象读取或写入文件。
  • 或者我发现了一个错误? -- 编译器中的一个错误?不,您的代码中有错误吗?是的。此外,如果您记下writeread 的最后一个参数,这将不起作用。 sizeof(A) 永远不会改变并且是编译时值。如果std::string 成员中有一百万个字符,sizeof(A) 将不会改变。
  • @UtkarshGupta 未定义的行为就是这样——未定义。如果您更改编译器选项,同样的代码可能会失败。
  • 另外,试试我提到的案例。将y 设为一千个字符而不是五个字符。您将看到您的代码失败。例如,m.y = std::string(1000, 'x'); 您在输出文件中看到 1,000 个“x”字符吗?

标签: c++ file-handling


【解决方案1】:

您的程序有未定义的行为。

你不能像std::string 这样的复杂对象按字节序列化。

未定义行为的结果可能会有所不同;在您的 Linux 安装中,您可能正在目睹“小字符串优化”,其中您的字符串数据小到足以放入一个小的就地缓冲区。这可以避免任何导致 Windows 崩溃的动态内存。也许 Windows 正在检测不良行为,或者它的 SSO 缓冲区较小,或者根本没有!

但无论哪种方式,代码仍然具有未定义的行为。

【讨论】:

    猜你喜欢
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 2017-08-18
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 2011-06-15
    相关资源
    最近更新 更多