Seven Ways To Improve Your C-Programs With GCC

14 Oct 2008

Recently, a colleague mentioned how they were having trouble with their server crashing and some of the errors were due to "functions missing return statements, printf mismatches, etc". Yikes!

A lot of common C programming gotchas can be eliminated just by using the GCC compiler in creative and not-so-creative ways. If you aren't using GCC, consider setting up an alternate build system to use it to find new errors you current compiler isn't finding. Most of these apply to C++ too.


There are a few more flags and tricks that can be done but these are the big ones.

Happy Compiling!

Use -Wall -Wextra -Werror now!

Without these flags, lovely code like this

int foo(int n) {
  if (n > 0)
    return 1;

is technically legal C, and compiles and links just fine. These flags will catch many of the dumb mistakes like this.

The one gotcha is that system or other library headers files might cause some troubles. This is very annoying, which has a few less than elegant hacks to fix, but keep those flags on. One developer I know relaxed (ahem, removed) these flags so he could compile against another library. Within hours bad code was checked in and flowing into production.

Add -Wformat=2

Bad printf-style format strings can cause core dumps or major security violations. This check greatly improves type checking. Not sure why this is not part of -Wall or -Wextra.

However, I'm not sure these checks can prevent 100% of the bad cases that can cause core dumps, but, it's better than no checks.

Use C99

Enable this with -std=c99. It's slightly more strict and deprecates some very old C idioms than nobody uses intentionally any more.

Compile using the latest gcc

Even if your production version uses a different compiler, it pays to compile using the latest gcc just to find errors. Every point release contains more checks. Version 4.3 is especially useful (most new checks are included in -Wall

Compile both production and debug builds regularly

I assure you deep inside your source code, someone has put in a #ifdef DEBUG. And, I assure you at some point a debug build will go into production. Or your developer will run exclusively a debug build not realizing they broke the production build.

On your build harness (you have one right?), build both debug and optimizers versions, and run the unit tests against both. It will find errors.

Consider compiling with C++

Ok, i know this is scary since once the gates are lifted, and C++ developers come out of their cage, your code base can get weird, fast. I'm not saying converting to C++, but just compiling it, just like you are compiling both a production and debug build. It will require some tinkering, and adding casts before malloc, but your code can compile cleanly under C99 and C++. The benefit is that C++ is much more strict on types and initialization than C99. It will find bugs.

Add -Wconversion

Added 20-Oct-2008: -Wconversion checks signed-to-unsigned (and vice-versa) conversions and automatic floating-point to integer. While this can initially produce a lot of warning, some quick cleanups will catch conversions that lose data or lose precision.

What are your compiler tricks to get better and safer code?