← C17 MOC · 🎯 Mission · 📖 Glossary · Lesson 0002
Standard I/O & Binary File Streams Reference (C17)
[!NOTE] Production Standards Low-level file stream management in C requires strict error code checking, binary mode flags, and understanding record-based reading (
sizevsnmemb).
1. Return Code Conventions in C
Unlike modern languages with exceptions or Result<T, E> types, C standard library functions use two distinct return conventions:
| Convention | Success Value | Error / Failure Value | Examples | Vault Cross-Reference |
|---|---|---|---|---|
| Status / Error Code | 0 (EXIT_SUCCESS) | Non-zero (or < 0, setting errno) | fseek(), fclose(), strcmp(), pthread_create() | Defensive Invariants |
| Value / Count / Handle | Valid object / count | NULL or EOF (-1) | fopen() (NULL), fread() (items read), ftell() (-1L) | Grill Diagnostic |
[!TIP] The
fseekCheck Pattern According to ISO C17 (§7.21.9.2),fseekreturns nonzero on failure. Always testif (fseek(f, offset, origin) != 0)to handle any non-zero error code portably.
2. Deep Dive: fread Parameters
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fread is designed for structured record reading, not just unstructured byte streams:
| Parameter | Type | Purpose | In Raw Byte Streams (e.g. ROMs) | In Structured Records (e.g. Structs) |
|---|---|---|---|---|
ptr | void* | Destination buffer address in memory. | &chip8->memory.memory[0x200] | player_array |
size | size_t | Size of a single element (in bytes). | sizeof(uint8_t) (= 1 byte) | sizeof(Player) (= 40 bytes) |
nmemb | size_t | Number of elements to read. | file_size (e.g. 512 bytes) | 10 (for 10 players) |
stream | FILE* | Open file stream handle. | file | file |
$$\text{Total Bytes Read} = \text{size} \times \text{nmemb}$$
Why size and nmemb are Split:
fread returns the number of whole elements successfully read (nmemb), not the raw byte count.
- If reading 10
Playerstructs (40 bytes each) and the file cuts off after 7 full structs (280 bytes),freadreturns7. - This enables instant validation:
if (fread(team, sizeof(Player), 10, f) != 10) { /* handle incomplete read */ }. - In CHIP-8 emulation, loading the binary ROM into RAM starting at
0x200directly maps to the CHIP-8 Memory Architecture.
3. Determining File Size Safely
// 1. Seek to end of file
if (fseek(file, 0, SEEK_END) != 0) {
// Error handling
}
// 2. Get byte offset
long file_size = ftell(file);
if (file_size <= 0) {
// Empty or non-seekable file
}
// 3. Always rewind before reading
rewind(file); // Equivalent to: fseek(file, 0, SEEK_SET);
4. Binary Mode ("rb") vs Text Mode ("r")
"rb"(Binary): Reads the raw bytes verbatim from disk into memory with zero transformation. Mandatory for ROMs, images, network payloads, and executables."r"(Text): The C runtime may translate newline sequences (e.g., converting\r\nto\non Windows or legacy systems), which will corrupt binary opcodes and shift memory offsets.
