Stream error handling

Error indicators

When an error happens during an operation on a stream, its internal error indicator is set. The following functions, when used on a stream, reset its error indicator: clearerr, rewind and freopen.

Streams also have an end of file indicator that is set when the stream tries to read a character while the end of the stream has been reached. The following functions reset that indicator: clearerr, rewind, fseek, fsetpos and freopen.

Checking for errors

The header of function used to check the error indicator of a stream is int ferror(FILE* stream). It takes the stream as argument and returns 0 (false) only if the error indicator is not set.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h> int main() { char data[] = {1, 2, 3, 4}; FILE* file = fopen("file.bin", "ab+"); // Write data to the file. fwrite(data, 1, 4, file); /* Verify if the error indicator of the stream 'file' is set. If it is, that would mean that an error occurred during the call of the function fwrite. */ if(ferror(file)) puts("The error indicator is set."); else puts("No error."); fclose(file); return 0; }

Resetting the error indicator of a stream

We saw, above, that there are 3 functions that reset the error indicator of a stream, but the header of the function which sole purpose is to do so is void clearerr(FILE* stream). It takes, in argument, the stream from which the error indicator will be reset.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h> int main() { char buffer[20]; // Open a file in write-only/binary mode. FILE* file = fopen("file.bin", "wb"); // Tries to read from an output-only stream. fread(buffer, 1, 20, file); // Here, the error indicator of 'file' is set. if(ferror(file)) puts("The error indicator is set."); else puts("No error."); // Resets the error indicator of 'file'. clearerr(file); if(ferror(file)) puts("The error indicator is set."); else puts("No error."); fclose(file); return 0; }

Retrieving information about an error

The C Standard Library defines a global variable named errno which can be set to an error code from any function of the C Standard Library when an error occurs. So, when an error happens during an operation on a stream, that value is set to a non-zero error code. If errno equals 0, that means that there is no error. Note that there is no function from the standard library that sets errno back to zero, so we must do it manually. Note that errno is declared in the header <errno.h>, so we must include it to be able to set its value.

The function which header is void perror(const char* str) is used to print a message describing the error (Which is different depending on the compiler used). The argument is a null-terminated string that will be displayed (Followed by a colon and a space) before the error message. If it receives a null pointer, only the error message will be displayed.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h> #include <errno.h> int main() { char data[] = {1, 2, 3, 4}; // Opening a file in read-only binary mode. FILE* file = fopen("test.bin", "rb"); // Tries to write to a read-only file. fwrite(data, 1, 4, file); // If the error indicator of file is set. if(ferror(file)) { // Prints the error message associated with the error-code from errno. perror("The following error happened"); // Reset the error indicator of file. clearerr(file); // We must manually set errno back to 0. errno = 0; /* The following call to perror will print a message stating that there is not error, because errno is set back to 0. */ perror("The following error happened"); } fclose(file); return 0; }

Checking the end of file indicator

Retrieving the state of the end of file indicator of a stream is made the same way as checking the error indicator, but by using the function which header is int feof(FILE* stream). It takes the stream from which the end of file indicator will be tested and it returns 0 if the indicator is not set.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h> int main() { // Open the file "file.txt" in read-only/text mode. FILE* file = fopen("file.txt", "r"); /* Here, feof will return 0 because even if the file is empty (So the cursor of the stream is at the end), an attempt to read a character must be done for the end of file indicator to be set. */ if(feof(file)) puts("The end of file indicator is set."); double num; // Reads a floating-point number (As a double) from 'file' to 'num'. fscanf(file, "%lf", &num); /* Here, feof will return a non-zero value if the file is either empty or contains only one number. */ if(feof(file)) puts("The end of file indicator is set."); fclose(file); return 0; }