fread/fwrite异常行为排查:Windows下文件读取结果不符问题
The character & Number of items read 6422304 Instead of Expected Output on Windows Let’s break down the root causes and what’s happening under the hood here—this is almost certainly a combination of Windows-specific file handling quirks and common code mistakes.
Most Likely Culprits
1. Wrong File Open Mode (Text vs. Binary)
Windows treats text and binary files differently, unlike Unix-like systems where there’s no distinction. When you use fopen("meta.dat", "r") (the default text mode), the C standard library does hidden conversions:
- Reads
\r\n(Windows line endings) as\n - Treats the byte
0x1A(Ctrl+Z, legacy Windows EOF marker) as an immediate end-of-file signal - Writes
\nas\r\n
If your meta.dat is a binary file (e.g., just a single byte 0x42 for 'B'), text mode might not corrupt that specific byte, but if your file accidentally contains a 0x1A (or if the code reads past the file’s actual end), it can truncate reads or pull in garbage data.
2. Misused fread Parameters (or Uninitialized Variables)
The fread function has a specific parameter order that’s easy to mix up:
size_t fread(void *ptr, size_t item_size, size_t num_items, FILE *stream);
- Return value = number of items successfully read (not bytes)
If you swapped item_size and num_items (e.g., using sizeof(int) instead of sizeof(char) for a single character read), you’d end up reading way more data than intended—possibly pulling in uninitialized stack memory.
The huge number 6422304 is a dead giveaway for an uninitialized variable. If your code declared int count; without setting it to 0 first, and fopen failed (common on Windows if your program’s working directory isn’t where you created meta.dat), count would hold random garbage from the stack instead of the actual fread return value.
3. Character Encoding & Console Mismatch
Windows consoles default to an OEM encoding (like CP850 or GBK) instead of UTF-8. While 'B' is 0x42 across most encodings, if your code is reading multi-byte data as single bytes (e.g., reading a UTF-16 file with char), you might get truncated bytes that map to '&' (0x26). That said, this is less likely than the first two issues.
What’s Actually Happening in Your Case
Let’s assume your code looks something like this (a common mistake):
#include <stdio.h> int main() { FILE *fp = fopen("meta.dat", "r"); // Text mode by default char c; int count; // Uninitialized! if (fp != NULL) { // Wrong: trying to read 1 item of size int (4 bytes) into a char count = fread(&c, sizeof(int), 1, fp); } printf("The character %c Number of items read %d\n", c, count); fclose(fp); return 0; }
- Uninitialized Variable: If
fopenfails (e.g., your program runs from a different directory thanmeta.dat),countnever gets set, so it outputs a random stack value like6422304. - Out-of-Bounds Read: Reading a 4-byte int into a 1-byte
charoverwrites adjacent stack memory, socends up with a random byte like0x26(which is '&'). - Text Mode Interference: If
meta.dathad a0x1Abyte, text mode would stop reading early, leading to unexpected return values.
Fixes to Try
- Initialize All Variables: Always set default values, e.g.,
int count = 0;. - Use Binary Mode for Binary Files: Open with
fopen("meta.dat", "rb")to skip Windows text conversions. - Correct
freadUsage: For a single character, use:
And use the correct format specifier forsize_t count = fread(&c, sizeof(char), 1, fp);size_t:printf("... %zu\n", count);. - Verify File Path & Content: On Windows, use absolute paths if unsure (e.g.,
fopen("C:\\your\\path\\meta.dat", "rb")), and check the file’s hex content to confirm it’s really0x42(the byte for 'B').
内容的提问来源于stack exchange,提问作者Artyom Gevorgyan

