In addition to writing code, a programmer needs to be adept at identifying and addressing errors. In this chapter, we will focus on errors in C programs. It’s important for programmers to spot errors before compiling. If any rules are missed, the compiler will throw error messages, and it’s the programmer’s job to resolve them for successful compilation. Sometimes, there are errors that the compiler can’t catch, and they only show up when the code is executed, leading to bugs and tricky problems. Programmers should be capable of dealing with any kind of error before it becomes critical. This chapter aims to explain and provide insights into different types of errors.
Note: Understanding error concepts can be challenging for beginners. However, as you gain more experience and become familiar with the C programming language, revisiting the topic of errors will help you understand them better.
Compile time errors
Compile-time errors, also known as compilation errors, are errors that occur during the compilation process. As we discussed the various stages of compilation, errors can occur in each stage. Let’s take a closer look at these stages and the corresponding errors
1. Preprocessing errors
During this stage, the compiler includes header files, performs macro replacements,and removes comments. Any incorrect usage in this stage results in preprocessing errors. For example, let’s consider the inclusion of the “stdio.h” header file for using standard input/output functions. If we mistakenly misspell it and include it like this:
#include <stdi.h>
Since the file “stdi.h” is not found, the compiler will generate an error message similar to the following:
myerrors.c:2:10: fatal error: stdi.h: No such file or directory
2 | #include <stdi.h>
| ^~~~~~~~
compilation terminated.
Any incorrect usage of preprocessor directives (discussed in the preprocessors chapter) can also lead to preprocessing errors.
2. Translating errors:
During the translation stage, the C code is converted into assembly code, and any grammatical errors are detected at this stage, which are referred to as syntax errors. Let’s consider an example where we missed a semicolon at the end of a statement, which is not a valid syntax in C, like this:
#include <stdio.h>
int main()
{
printf(“onesandzeroverse.com\n”)
}
This would result in an error message similar to the following:
error: expected ‘;’ before ‘}’ token
printf(“onesandzeroverse.com\n”)
| ^
| ;
| }
Any statements that do not conform to the rules of the C language will result in syntax errors.
3. Assembling errors
As translator already checks the syntax errors, in this stage the assembly code converts to object code. This stage is error free stage in compilation.
4. Linking errors
In this stage, all the functions are linked together. It checks whether a function is defined within the same program or in the C library. Any incorrect usage of functions or missing function definitions is detected by the compiler at this stage. Let’s understand this with an example program and go through each stage of compilation:
#include <stdio.h>
int main()
{
myfunction();
}
The above program calls myfuntion() which is not defined anywhere. Lets go through each stage of compilation and check what happens
1. Preprocessing stage:
No errors occur during the preprocessing stage. To preprocess the code, you would use the command:
gcc -E test.c -o test.i
2. Translator stage:
During this stage, the following warning is generated:
gcc -S test.i -o test.s
test.c:45:2: warning: implicit declaration of function ‘myfunction’ [-Wimplicit-function-declaration]
45 | myfunction();
| ^~~~~~~~~~
This warning occurs because the translator has no knowledge of the type of the myfunction( ) function. However, the compilation process continues as it is just a warning. But this can be solved as shown below.
#include <stdio.h>
void myfunction(void);
int main()
{
myfunction();
}
By the above correction this translator error is eliminated as the translator can understand the type of function by the prototype declared above.
3. Assembler stage
No errors occur during the object file generation stage. To generate the object file, you would use the command:
gcc -c test.s -o test.o
4. Linker stage
During the linking stage, the following error is encountered, and the compilation is halted:
gcc test.o -o test
/usr/bin/ld: test.o: in function `main':
test.c:(.text+0x187): undefined reference to `myfunction'
collect2: error: ld returned 1 exit status
This error is detected by the linker, indicating that the definition of myfunction is not known to the linker, causing the compilation to fail.
Run time errors in C
Run-time errors are a type of error that occur during the execution of the code. Unlike compile-time errors, these errors cannot be detected by compilers. It is the responsibility of the programmer to anticipate and prevent these errors to ensure smooth execution of the program.
These examples demonstrate common runtime errors that can occur during the execution of C programs.
1. Division by zero
int a = 10;
int b = 0;
int result = a / b; // This will cause a runtime error
2. Accessing an out-of-bounds array index
int arr[3] = {1, 2, 3};
int value = arr[5]; // This will cause a runtime error as arr[5] is out of bounds
3. Using an uninitialized variable
int x;
int sum = x + 5; // This will cause a runtime error as x is uninitialized and it may contain garbage value
4. Null pointer dereference
int* ptr = NULL;
int value = *ptr; // This will cause a runtime error as NULL pointer is being dereferenced