6

This C++ code is intended to move the data from 67 ~ 69 to 70 ~ 72 in the file:

#include <fstream>
#include <iostream>

int main() {
  std::fstream file("test", std::ios::out);
  file.close();
  file.open("test", std::ios::binary | std::ios::in | std::ios::out);
  for (char i = 0; i < 127; ++i) 
    file.write(&i, 1);

  file.seekp(70);
  file.seekp(-3, std::ios::cur);

  char s[100];
  for (int i = 0; i < 100; ++i)
    s[i] = '\0';

  file.read(s, 3);
  for (int i = 0; i < 3; ++i)
    std::cout << (int)s[i] << " ";

  std::cout << std::endl;

  file.write(s, 3);
  file.seekp(-3, std::ios::cur);
  file.read(s, 3);

  for (int i = 0; i < 3; ++i)
    std::cout << (int)s[i] << " ";

  std::cout << std::endl;
}

The content of s should be the same in the two times I read it, just as the output if we compile the code in g++:

67 68 69
67 68 69

But the result in Visual Studio is different:

67 68 69
70 71 72

Is there any undefined behavior involved that leads to the bug? How should I fix it?

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • 1
    correct output with [clang](https://wandbox.org/permlink/wIrSY51bPWxSu0Et) – 463035818_is_not_an_ai Dec 10 '18 at 12:36
  • Does this happen on Windows? – user7860670 Dec 10 '18 at 12:53
  • @Someprogrammerdude But shouldn't the write-pointer and read-pointer of an `fstream` object always be at the same position? – Zhiyang Xun Dec 10 '18 at 12:55
  • @ZhiyangXun apparently not, read the documentation. I wasn't aware of this either. – Jabberwocky Dec 10 '18 at 12:56
  • @VTT yes, it's on Windows – Zhiyang Xun Dec 10 '18 at 12:56
  • Are there any reason for writing `i` variable address file.write(`&i`, 1); instead of writing a byte value. G++ and MS CL optimizing loops differ etc. – Victor Gubin Dec 10 '18 at 12:59
  • 1
    `basic_filebuf` specifies that *A joint file position is maintained for both the input sequence and the output sequence.* – user7860670 Dec 10 '18 at 13:05
  • first 3 lines in `main`: why??? – Andriy Tylychko Dec 10 '18 at 13:06
  • I suggest you print the file position (`tellp` or `tellg`, perhaps *both*) before and after every seek, read and write. Also print the result of `gcount` after every read, and make sure that the file status is alright as well (`if (!file) { error... }`) – Some programmer dude Dec 10 '18 at 13:24
  • 1
    @AndriyTylychko `std::ios::in` requires the file to exist. See the table [here](https://en.cppreference.com/w/cpp/io/basic_filebuf/open) – Lightness Races in Orbit Dec 10 '18 at 13:31
  • 2
    under VS `file.write(s, 3);` step fails or rather seems to write at 67 pos (even though output position is updated to 70), adding `file.seekp(70);` fixes the situation while `flush` does not – user7860670 Dec 10 '18 at 13:34
  • 2
    Related: https://stackoverflow.com/a/17567454/560648 though I don't think that's the situation here as you are seeking. Still, the topic may provide some clues. – Lightness Races in Orbit Dec 10 '18 at 13:35
  • @Someprogrammerdude I did what you suggested and `tellg` and `tellp` are always the same, and the result of `gcount` is also correct. The file status is consistently alright as well. – Zhiyang Xun Dec 10 '18 at 13:45
  • Does it give you any hints about what's going on? Are the positions what you expect them to be? – Some programmer dude Dec 10 '18 at 13:47
  • @VTT Thank you so much! I've checked output position and tried flushing before writing but neither solved my problem. Do you know the reason? – Zhiyang Xun Dec 10 '18 at 13:49
  • I guess this is duplicated after all – user7860670 Dec 10 '18 at 13:51
  • @Someprogrammerdude They are at the positions I expected to be... VTT's answer explains the situation. – Zhiyang Xun Dec 10 '18 at 13:52
  • @VTT But if I add a flush before writing, it will not violate the restriction. Why won't that solve the problem? – Zhiyang Xun Dec 10 '18 at 14:04
  • From answer to that question *"input shall not be directly followed by output without an intervening call to a file positioning function, unless the input operation encounters end- of-file."* – user7860670 Dec 10 '18 at 14:05
  • This should not have been closed. MSVC is misapplying limitations on seeking in string buffers to the underlying file buffer. See §30.8.2.4 [stringbuf.virtuals] where `cur`-relative seeks are defined to fail on `in|out` stringbuffers and §30.9.2.4 [filebuf.virtuals] where they're not, because you can (and do, here) have binary files where cur-relative seeks work, while binary strings are still an oxymoron, at least in the C family. – jthill Dec 10 '18 at 14:16

0 Answers0