Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does visual studio give another result than g++ ? Is Undefined behavior involved here? [duplicate]

I have a file that already contains some data (say, 8 kB). I want to read something from the beginning of the file, and then overwrite data starting where I finished reading. So I try to use the following code:

std::fstream stream("filename", std::ios::in | std::ios::out | std::ios::binary);

char byte;
stream.read(&byte, 1);

// stream.seekp(1);

int bytesCount = 4096;

auto bytesVec = std::vector<char>(bytesCount, 'c');
char* bytes = bytesVec.data();

std::cout << stream.bad() << std::endl;

stream.write(bytes, bytesCount);

std::cout << stream.bad() << std::endl;

If I execute this code, the first bad() returns false, but the second one returns true and nothing actually gets written.

If I decrease bytesCount to anything smaller than 4096 (presumably the size of some internal buffer), the second bad() returns false, but still nothing gets written.

If I uncomment the seekp() line, the writing starts working: bad() returns false and the bytes actually get written.

Why is the seekp() necessary here? Why doesn't it work without it? Is the seekp() the right way to do this?

I'm using Visual Studio 2012 on Windows 7.

like image 755
svick Avatar asked Jul 08 '13 21:07

svick


People also ask

What is undefined behaviour in c++?

So, in C/C++ programming, undefined behavior means when the program fails to compile, or it may execute incorrectly, either crashes or generates incorrect results, or when it may fortuitously do exactly what the programmer intended.

Why is my variable uninitialized in c++?

Uninitialized means the object has not been given a known value (through any means, including assignment). Therefore, an object that is not initialized but is then assigned a value is no longer uninitialized (because it has been given a known value).

What is an undefined reference unresolved external symbol error and how do I fix it?

So when we try to assign it a value in the main function, the linker doesn't find the symbol and may result in an “unresolved external symbol” or “undefined reference”. The way to fix this error is to explicitly scope the variable using '::' outside the main before using it.

What kind of error is unresolved external symbol?

The compiler can identify when a symbol isn't declared, but it can't tell when the symbol isn't defined. It's because the definition may be in a different source file or library. If a symbol is referred to but never defined, the linker generates an unresolved external symbol error.


2 Answers

You are falling foul of a restriction upon the intermixing of read and write operations on a file opened in update mode that MS's fstream library inherits from from the its C <stdio.h> implementation.

The C Standard (I cite C99, but it doesn't differ in this point from C89) at 7.19.5.3/6 states:

When a file is opened with update mode ('+' as the second or third character in the above list of mode argument values), both input and output may be performed on the associated stream. However, output shall not be directly followed by input without an intervening call to the fflush function or to a file positioning function (fseek, fsetpos, or rewind), and 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.

(my emphasis).

So your stream.seekp(1) solution, which devolves to a C fseek, is correct.

The GNU C library does not have this Standard limitation, so your code as posted works as expected when built with GCC.

The MS <fstream> library is compliant with the C++ Standard in inheriting this restriction. fstreams are implemented using basic_filebuf<charT,traits>. In the (C++11) Standard's account of this template, at § 27.9.1.1/2, it simply says:

The restrictions on reading and writing a sequence controlled by an object of class basic_filebuf are the same as for reading and writing with the Standard C library FILEs.

like image 137
Mike Kinghan Avatar answered Oct 06 '22 01:10

Mike Kinghan


You may want to look into tied streams - http://www.cplusplus.com/reference/ios/ios/tie/

This makes every time an input reads the output will automatically be flushed, which is I think the behavior you want, although it does require a separate input and output stream

like image 29
Rand McRanderson Avatar answered Oct 06 '22 00:10

Rand McRanderson