Yulong Tian
Yulong Tian

Reputation: 107

Confusion with fwrite in VC2012

I need to write some binary data into file. The format is uint64_t.

  #include <stdio.h>
  #include <assert.h>
  typedef unsigned long long uint64_t;

  int main()
  {
    FILE * file = fopen("data","w");assert(file);
    uint64_t a[]={16000550, 1051320,14456018, 4743184,11840752 ,4225032,\
                      13642264,6059108,563784 ,11823354,3989084 ,15759410,\
                      13413018 ,1582802,1574952 ,1635384,1102996 ,10511428,\
                      10239562 ,9472574,2641952 ,1350256,3432142 ,9920,11573360,\
                      12121180,10255874 ,3198684,7628524,16522766,12908660,\
                      2681374,9482820 ,6354462,15230702 ,16255676,5813862, \
                      8174782,7642752,7362790,6089340 ,803928,2669686 ,4225032,\
                      7603956 ,16551562,15734364 ,14424308,12060282 ,572450,\
                      18432 ,10276902,8134910 ,10749010,14166126 ,1636942,\
                      5295788 ,12342876,2151156 ,12322948};
     for(int i=0;i<sizeof(a)/sizeof(uint64_t);i++)
     {
    fwrite((char*)&a[i],sizeof(uint64_t),1,file);
     }
         fclose(file);
  }

I found the output doesn't satisfy my expectation only when the size of array is large, so I give 60 uint64_ts in my example.

In test, I found it will output 0000 fe20 7c00 0000 for 8134910. Also, some others errors exists in it. In GCC, it works well and in VS2012, it works bad.

Upvotes: 2

Views: 111

Answers (1)

Roger Rowland
Roger Rowland

Reputation: 26279

Based on your feedback in comments, the reason it's different in VS2012 is because the file has been opened by defualt in "text" mode. In this mode, each \n when written will be expanded to \r\n, which will corrupt your data.

The solution is to explicitly open the file in binary mode:

FILE * file = fopen("data","wb")

Quoting from MSDN regarding the t and b characters that may be appended to the mode:

t

Open in text (translated) mode. In this mode, CTRL+Z is interpreted as an EOF character on input. In files that are opened for reading/writing by using "a+", fopen checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using fseek and ftell to move within a file that ends with CTRL+Z may cause fseek to behave incorrectly near the end of the file.

In text mode, carriage return–linefeed combinations are translated into single linefeeds on input, and linefeed characters are translated to carriage return–linefeed combinations on output. When a Unicode stream-I/O function operates in text mode (the default), the source or destination stream is assumed to be a sequence of multibyte characters. Therefore, the Unicode stream-input functions convert multibyte characters to wide characters (as if by a call to the mbtowc function). For the same reason, the Unicode stream-output functions convert wide characters to multibyte characters (as if by a call to the wctomb function).

b

Open in binary (untranslated) mode; translations involving carriage-return and linefeed characters are suppressed.

If t or b is not given in mode, the default translation mode is defined by the global variable _fmode.

The MSDN documentation for _fmode says:

The default setting of _fmode is _O_TEXT for text-mode translation. _O_BINARY is the setting for binary mode.

Upvotes: 2

Related Questions