0

hi,

I've just done something like below in c++: - ON - WINDOWS 10

   //1. Serialize a number into string then write it to file
        std::string filename = "D:\\Hello.txt";
        size_t OriNumber = 26;
        std::string str;
        str.resize(sizeof(size_t));
        memcpy(&str[0], reinterpret_cast<const char*>(&OriNumber), str.size());

        std::ofstream ofs(filename);
        ofs << str << std::endl;
        ofs.close();

        //2. Now read back the string from file and deserialize it
        std::ifstream ifs(filename);
        std::string str1{std::istreambuf_iterator<char>(ifs), std::istreambuf_iterator<char>()};

        // 3. Expect that the string str1 will not be empty here.
        size_t DeserializedNumber = *(reinterpret_cast<const size_t*>(str1.c_str()));
        std::cout << DeserializedNumber << std::endl;

At step 3, I could not read the string from file, even if I opened the file with notepad++, it showed several characters. At last line we still have the value of DeserializedNumber got printed, but it is due to str1.c_str() is now a valid pointer with some garbage value.

After debugged the program, I found that std:ifstream will get the value -1(EOF) at beginning of the file, and as explanation of wikipedia, 26 is value of Substitue Character and sometime is considered as EOF.

My question is:

  1. if I can't read value 26 from file as above, then how can serialization library serialize this value to bytes?
  2. and Do we have some way to read/write/transfer this value properly if still serialize the value 26 as my way above?

thanks,

van con Nguyen
  • 101
  • 1
  • 5
  • 1
    `memcpy(&s[0], reinterpret_cast(&OriNumber), s.size());` My Undefined-Behaviour-o-meter run out of scale on this line. What are you trying to achieve here? And are you sure you need a text file and not a binary file? – Yksisarvinen Jun 19 '19 at 10:41
  • 1
    The `*(reinterpret_cast...` has undefined behaviour. Use `memcpy` like you did when writing. – molbdnilo Jun 19 '19 at 10:51
  • Why don't you just [write](https://en.cppreference.com/w/cpp/io/basic_ostream/write) and [read](https://en.cppreference.com/w/cpp/io/basic_istream/read) the `size_t`? – molbdnilo Jun 19 '19 at 10:52
  • After fixing the compilation errors, that code outputs `26` for me. Please post a [mcve]. – molbdnilo Jun 19 '19 at 11:04
  • @Yksisarvinen, why undefined behavior? According to [this post](https://stackoverflow.com/questions/1986966/does-s0-point-to-contiguous-characters-in-a-stdstring) it's rather safe to assume that `&[s0]` points to contiguous memory. `reinterpret_cast` also looks ok, although I would rather cast to `const void*`. Similar tricks are used when dealing with big endian vs little endian archs. – pptaszni Jun 19 '19 at 11:58
  • 1. I haven't tested this issue on linux yet. but it is happening on windows(10), and the str1 is read as empty string. I've edited the my code sample, and it is compilable now. 2. I think that you got undefined behavior by missing this line ```str.resize(sizeof(size_t));```. till now. it is working well with my on both MSVC++ and MingW-GCC. and the syntax is valid. 3. @molbdnilo: I want to read entire file to memory instead of read byte to byte or line by line(this is a small example, in real code it is a bigger file). then I used iterator instead. thanks. – van con Nguyen Jun 19 '19 at 12:06
  • 1
    For me it works on Debian9, valgrind doesn't complain. Maybe try to use `ofs(filename, std::ios::binary)` ? – pptaszni Jun 19 '19 at 12:16
  • On windows the default stream read/write mode is text. Do as Ptag666 suggested. See [here](https://learn.microsoft.com/en-us/cpp/standard-library/binary-output-files?view=vs-2019) for reference. – Gabriella Giordano Jun 19 '19 at 13:39
  • Thanks for suggestion, I tested on linux, It can read the character 26 into memory but ignore rest of the file. it is a little bit different that windows that in windows it reads nothing into memory. Then I'm looking for a suggestion to read entire file without ignoring all subsequent chars after '26'. thanks, – van con Nguyen Jun 19 '19 at 14:35
  • Finally, I had an idea to solve the problem. 1. when write the file, write the buffer's size first: ```ofs << str.size() << str << std::endl;``` 2. when read the file, read the buffer's size first then allocate memory to read entire the file: ```size_t size; ifs >> size; if(size) { str1.resize(size); ifs.read(&str1[0], size); } ``` This works quite perfect. then thanks all of you for your ideas! – van con Nguyen Jun 19 '19 at 14:54
  • @van con Nguyen: `ofs << str.size() << str << std::endl;` will not work if str begins with a digit. Your code for reading will then try to read too much. You have to insert some kind of delimiter between str.size() and str and skip it when reading back. – Marko Mahnič Jun 19 '19 at 17:45

0 Answers0