7 Common Errors in C Programming and C++ Programming
C and C++ are two of the most widely-used software languages — especially for embedded systems. The C and C++ programming languages are highly expressive and flexible. But they’re open to interpretation in application.
This means that programming in C/C++ is often prone to errors. To help you avoid potential errors in C programming and C++ programming, review the following guidance.
Read along or jump ahead to the section that interests you the most:
➡️ Improve c and c++ code with Static Analysis
Back to topWhat Are Errors in C Programming and C++ Programming?
Errors in C programming and C++ programming often happen when there's undefined behavior or human error.
Undefined behavior occurs:
- Where language definition is unclear.
- Where no outcome specification has been defined.
- Where the compiler or library vendor has some explicit freedom of implementation.
But most coding errors are introduced by developers. They can be caused by anything from suspect coding assumptions to a plain lack of foresight.
➡️ 📝 Sign up now for an on-demand Helix QAC and/or Klocwork demo
Back to top7 Types of Errors in C Programming and C++ Programming
Here are seven common errors in C programming and C++ programming.
1. Initialization
Data initialization is always important. And it’s especially important with complex C++ data structures.
It's easy to forget to initialize class members. Here’s an example of an initialization error in C++:
class A {
public:
A () {} // does not init 'm_i'
int getI () const;
private:
int m_i;
};
int j = A() .getI (); // 'm_i' (and subsequently j)
// have indeterminate value
How to Avoid Initialization Errors in C Programming
You can avoid this kind of error with a coding rule like this one:
Constructors shall initialize (either through initial value or constructor call) each base class and all non-static data members.
2. Name-Hiding
Name-hiding of declarations is a particularly difficult bug. In this error, the identifier at the innermost scope hides any matching name in an outer scope. This could be intentional — or not.
Consider this C++ for-loop example:
void foo (void)
{
int i = 15
int MyArray[10] ;
for (int i=0; i<10; ++i)
{
MyArray[i] = 0;
}
. . .
// whatever was intended . .
MyArray [i-1] = 1;
// .. out-of-bounds results
}
How to Avoid Name-Hiding Errors in C Programming
You can avoid name-hiding errors with the right coding rules.
Here’s an example:
An identifier in an inner scope shall not hide an outer scope identifier.
This helps to avoid a number of buggy and dangerous practices.
3. Boolean Expressions
The 1990 ISO version of the C language (C90) is still widely used today. There is no native boolean type in this version. And developers must circumvent this shortcoming with 'boolean-like' concepts.
The resulting lack of type safety can lead to some subtle yet dangerous bugs:
x = ( (a > b) & (c > d) );
/* logical rather than */
/* bitwise AND intended */
y = ( (a + b) || (c-d) );
/* odd: logical OR of two */
/* arithmetic expressions */
How to Avoid Boolean Expression Errors
These can be neatly avoided with the following coding rule.
Prohibit the mixing of arithmetic and logical (effectively Boolean) expressions.
4. Logic Flaws
Logic flaws can lead to serious errors, too.
if (y=x) { . . . }
// assignment or '==' meant?
For example, an assignment in a conditional expression. It's entirely legal. But this logic flaw can betray a syntax error or expose more complex logic issues.
In the next example, there’s a conditional evaluation.
if ( ( a == b) || (c = d) ) { . . . }
// conditional side-effect?
The Logical Or (||) represents a sequence point. So, the right-hand side expression will only be evaluated (and the assignment performed) if the left-hand side expression is false.
5. Unreachable Code
Unreachable code is code that will never be executed. It can indicate a logic error.
Here is a simple example:
int func(int a)
{
int b = a*2;
return b;
// Unreachable code
if (b < 10)
{
b += 10;
}
return b;
}
Another example is switch statements. Switch statements are an elegant control-flow C language mechanism.
The switch and case expressions must be of the same type and signedness. If they don’t, you may suffer implicit conversions.
Here’s an example.
unsigned char c;
. . .
switch ( c ) {
case -1:
. . . /* unreachable */
case 256:
. . . /* unreachable */
How to Avoid Unreachable Code
Apply a generic rule that a project shall not contain unreachable code. This is an undecidable rule — which means that it is not possible for an algorithm to detect all unreachable code with absolute certainty.
However, static analysis tools such as Helix QAC can flag definite, as well as possible unreachable code fragments.
6. Type Conversions
Type system flexibility is both a strength and a weakness of the C and C++ languages. But it’s often not understood. And it sometimes revealing difficult, value-sensitive bugs:
uint16_t u16a = 40000;
uint16_t u16b = 30000;
uint32_t u32a;
u32a = u16a + u16b;
// result value: 70000 or 4464?
The balancing and promotion rules of C/C++ might result in either of these values. It depends on how these two typedefs are defined. (An integer size of 16 bits will likely cause an error — even if the result size is set to a 32-bit type.)
How to Avoid Type Conversions
You can avoid these type conversions with the right coding rules, such as:
MISRA C Rule 10.6: "The value of a composite expression shall not be assigned to an object with wider essential type"
7. Casting Away CONST
Casting away the const qualification of a pointer allows a program to modify the object referred to by the pointer. This may result in undefined behavior.
// pointer to int:
int *pi;
// pointer to const int:
const int *pci;
. . .
// constraint error
pi = pci
// dangerous but permitted
pi = (int *)pci;
How to Avoid Casting Away CONST
You can avoid casting away CONST with the right coding rule, such as:
No cast shall be allowed that removes const or volatile qualification from the type addressed by a pointer.
Back to topHow to Prevent Errors in C Programming and C++ Programming?
These are just some of the most common errors in C programming and C++ programming. But there are hundreds to thousands of potential errors.
The only way to avoid these errors and ensure safe, secure, and reliable code is to use a coding standard. And it's best to apply it with the help of a static code analyzer, such as Helix QAC for C/C++ and Klocwork for C, C++, C#, Java, JavaScript, Python, and Kotlin.
➡️ start your free static analysis trial
Back to top