Image Blog QAC Errors CPP Programming
July 12, 2016

7 Common Errors in C Programming and C++ Programming

Coding Best Practices
Static Analysis

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 top

What 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 top

7 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 top

How 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