Skip to content
C Basics: Distinguish a Short Binary Read from an Error

C Basics: Distinguish a Short Binary Read from an Error

November 1, 2026

A short read is not automatically an I/O error. Read a small binary stream into a larger buffer and check why fewer bytes arrived.

Prepare a scratch directory

Tested on Linux amd64 with GCC 14.2.0. Install GCC and make gcc available on PATH. You also need Bash, a text editor, and the standard mktemp, rm, and rmdir utilities. This example uses the C standard library.

Keep the same terminal open. Stop if setup fails, before saving the source:

start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1

Run the example

Save this as fread-stream-status-demo.c:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const unsigned char original[] = {0x41, 0x00, 0xff};
    unsigned char received[8];
    FILE *stream = tmpfile();
    if (stream == NULL) {
        perror("tmpfile");
        return EXIT_FAILURE;
    }
    if (fwrite(original, 1, sizeof original, stream) != sizeof original ||
        fseek(stream, 0, SEEK_SET) != 0) {
        perror("prepare stream");
        fclose(stream);
        return EXIT_FAILURE;
    }
    size_t received_count = fread(received, 1, sizeof received, stream);
    printf("Bytes read: %zu\n", received_count);
    for (size_t index = 0; index < received_count; ++index) {
        printf("%02X%s", (unsigned int)received[index],
               index + 1 == received_count ? "\n" : " ");
    }
    int failed = ferror(stream) != 0;
    printf("EOF: %d; error: %d\n", feof(stream) != 0, failed);
    if (fclose(stream) != 0) {
        perror("fclose");
        return EXIT_FAILURE;
    }
    return failed ? EXIT_FAILURE : EXIT_SUCCESS;
}

Compile and run it. The second command runs only after compilation succeeds:

gcc -std=c17 -Wall -Wextra -Werror -pedantic fread-stream-status-demo.c -o fread-stream-status-demo &&
./fread-stream-status-demo

Observed output:

Bytes read: 3
41 00 FF
EOF: 1; error: 0

Read the result

Using an element size of one makes the return value a byte count. Only those bytes are printed; the unused part of the buffer is never read. The request exceeds the three-byte file, so the EOF indicator is set while the error indicator stays clear. The zero byte is ordinary binary data.

Apply it carefully

Check the read result first, then stream status. Do not use a pre-read EOF test as the loop condition. An exact-size read can succeed without setting EOF until a later read attempts to pass the end. This example demonstrates the EOF path, not an injected read failure. The temporary stream is removed when closed.

The official reference documents the behavior used here.

Clean up

Remove only the source and executable created for this example, then return to the starting directory:

rm -- fread-stream-status-demo.c fread-stream-status-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directory

If the directory is not empty, inspect its remaining contents before removing anything else.

Acknowledgements

This post was created with assistance from AI.

Last updated on