Programming Style

An important part of writing good code is using good style. Both C and C++ ignore most whitespace as a language so you can technically write the entire program on one line with almost no spaces. For the sake of being able to read your code again, this is almost never a good idea. However, this does mean that you have a lot of flexibility in how the code looks visually. The exact details of how your code looks is what we call your programming “style”.

I am not going to tell you to one specific style. There are as many different styles as there are programmers. I do, however, recommend that you pick a style that you like and stick to it. What follows is a brief guide to the kinds of things to think about when it concerns style.

Components of programming style

A given programming style can be broken down into how you handle certain cases. While there are probably more ways to break it down than I’m going to describe here, I’ll try and cover the basics.

Indentation

Probably the most obvious and important component of any style is indentation. You can write code like this:

#include <stdio.h>
int main(int argc, char **argv) {
int i;
printf("Hello World! Let me count to 10\n");
for (i = 1; i <= 10; ++i) {
printf("%d\n", i);
}}

While this works, if your program gets very long, it gets almost impossible to read. Usually programmers indent blocks of code with each block indented more than the one around it. For example, I would indent the above chunk of code as follows:

#include <stdio.h>
int
main(int argc, char **argv)
{
    int i;
    printf("Hello World! Let me count to 10\n");
    for (i = 1; i <= 10; ++i) {
        printf("%d\n", i);
    }
}

As you can see, this makes the blocks stand out much better and makes the code easier to read. How far you indent and exactly what blocks get indented is a matter of personal taste.

Curly Braces

Another important component of any C/C++ style is the placing of braces. In C/C++, braces denote blocks of code. Some people prefer to put the brace at the end of the line that starts the block, others prefer to put it on its own line. Exactly how it’s handled frequently depends on the type of block. For instance, a programmer may put the opening brace associated with a function declaration on its own line but put braces associated with if statements and loops on the same line as the statement.

For if statements, one thing to consider is how to handle the else condition. For example

if (ptr != NULL) {
    /* Do something with ptr */
} else {
    /* Handle the null pointer error */
}

vs

if (ptr != NULL)
{
    /* Do something with ptr */
}
else
{
    /* Handle the null pointer error */
}

or

if (ptr != NULL) {
    /* Do something with ptr */
}
else {
    /* Handle the null pointer error */
}

The problem with control statements like these is that different placements of the curly braces work better than others depending on the code in the block and whether or not the condition wraps onto another line. Different people also have different (and frequently strong) preferences on what they think looks better and is most readable.

Function Declarations

The two major parts of function declarations are the return value and the opening curly brace. Different programmers will put one, both, or neither of these on its own line. For example:

int main(int argc, char **argv) {
    printf("Hello World!\n");
}

vs.

int
main(int argc, char **argv) {
    printf("Hello World!\n");
}

vs.

int
main(int argc, char **argv)
{
    printf("Hello World!\n");
}

Switch Statements

The switch statement is a bit of a special case because of the labels. I would recommend doing the curly braces the same as with other control flow statements but the real problem is indentation. There are three different ways this is commonly done:

switch (c) {
    case 'h':
    print_help();
    return 0;
    case 'r':
    recursive = 1;
    break;
    default:
    fprintf(stderr, "Invalid Argument");
    print_help();
    return 1;
}

vs.

switch (c) {
case 'h':
    print_help();
    return 0;
case 'r':
    recursive = 1;
    break;
default:
    fprintf(stderr, "Invalid Argument");
    print_help();
    return 1;
}

vs.

switch (c) {
    case 'h':
        print_help();
        return 0;
    case 'r':
        recursive = 1;
        break;
    default:
        fprintf(stderr, "Invalid Argument");
        print_help();
        return 1;
}

One thing to consider is that if you chose the third option is that, if you indent a long ways, switch statements get double-indented. This can be a problem if you care about your code getting indented too far.

Line Wrapping

Sometimes a line of code will begin to get long enough that it won’t fit on one line. In this case, you have to decide if you will make it two lines or just let the text editor wrapper and where you will break the line. Personally, I try and make sure lines are no more than 80 characters so that they don’t unnaturally wrap in a standard-width terminal. Many people would consider my indenting habits to be quite extreme especially if you work in a graphical or full-screen text editor. How you handle this is up to you.

Examples of different programming styles

My personal style

This is an example of my personal style. Most of the code I write looks something like this (although sometimes I do something a little different for various reasons.)

#include <stdlib.h>
#include <stdio.h>

int
main(int argc, char ** argv)
{
    int i;
    char * arg;

    for (i = 0; i < argc; ++i) {
        /* Check to see if it's a one-letter flag */
        if (argv[i][0] == '-' && argv[i][1] != '\0' && argv[i][2] == '\0') {
            switch(argv[i][1]) {
            case 'h':
                /* Help flag */
                printf("This is the program help.");
                return 0;
            case 'n':
            case 's':
            case 'd':
                /* Normally we would do something specific for each one of
                 * these */
                printf("The -%c flag\n", argv[i][1]);
                break;
            default:
                printf("\"-%s\" is not a valid one-letter flag\n", argv[i][1]);
                return 1;
            }
        } else if (argv[i][0] == '-' && argv[i][1] == '-') {
            /* Get rid of the first 2 characters (both are '-') */
            arg = argv[i] + 2;

            /* Normally we would do some parsing here */
            printf("The --%s flag\n", arg);
        } else {
            /* Everything else we simply treat as a parameter */
            printf("\"%s\" as a parameter\n", argv[i]);
        }
    }
}

Expanded Style

Here is an example of something similar to my preferred style. This one isn’t quite as compact. Some people prefer a more “open” feel.

#include <stdlib.h>
#include <stdio.h>

int
main(int argc, char ** argv)
{
    int i;
    char * arg;

    for (i = 0; i < argc; ++i)
    {
        /* Check to see if it's a one-letter flag */
        if (argv[i][0] == '-' && argv[i][1] != '\0' && argv[i][2] == '\0')
        {
            switch(argv[i][1])
            {
                case 'h':
                    /* Help flag */
                    printf("This is the program help.");
                    return 0;

                case 'n':
                case 's':
                case 'd':
                    /* Normally we would do something specific for each one of
                     * these */
                    printf("The -%c flag\n", argv[i][1]);
                    break;

                default:
                    printf("\"-%s\" is not a valid one-letter flag\n", argv[i][1]);
                    return 1;
            }
        }
        else if (argv[i][0] == '-' && argv[i][1] == '-')
        {
            /* Get rid of the first 2 characters (both are '-') */
            arg = argv[i] + 2;

            /* Normally we would do some parsing here */
            printf("The --%s flag\n", arg);
        }
        else
        {
            /* Everything else we simply treat as a parameter */
            printf("\"%s\" as a parameter\n", argv[i]);
        }
    }
}

GNU Style

This is the style described in the GNU coding standards and used in the source code for the GNU toolchain. I personally don’t recommend it because I think it’s ugly, but it’s a good example of some of the variety you may see.

#include <stdlib.h>
#include <stdio.h>

int
main (int argc, char **argv)
{
  int i;
  char *arg;

  for (i = 0; i < argc; ++i)
    {
      /* Check to see if it's a one-letter flag */
      if (argv[i][0] == '-' && argv[i][1] != '\0' && argv[i][2] == '\0')
    {
      switch (argv[i][1])
        {
        case 'h':
          /* Help flag */
          printf ("This is the program help.");
          return 0;
        case 'n':
        case 's':
        case 'd':
          /* Normally we would do something specific for each one of
           * these */
          printf ("The -%c flag\n", argv[i][1]);
          break;
        default:
          printf ("\"-%s\" is not a valid one-letter flag\n", argv[i][1]);
          return 1;
        }
    }
      else if (argv[i][0] == '-' && argv[i][1] == '-')
    {
      /* Get rid of the first 2 characters (both are '-') */
      arg = argv[i] + 2;

      /* Normally we would do some parsing here */
      printf ("The --%s flag\n", arg);
    }
      else
    {
      /* Everything else we simply treat as a parameter */
      printf ("\"%s\" as a parameter\n", argv[i]);
    }
    }
}

Berkeley indent style

This is the style produced by the Berkely UNIX indent command.

#include <stdlib.h>
#include <stdio.h>

int
main(int argc, char **argv)
{
    int             i;
    char           *arg;

    for (i = 0; i < argc; ++i) {
    /*
     * Check to see if it's a one-letter flag 
     */
    if (argv[i][0] == '-' && argv[i][1] != '\0' && argv[i][2] == '\0') {
        switch (argv[i][1]) {
        case 'h':
        /*
         * Help flag 
         */
        printf("This is the program help.");
        return 0;
        case 'n':
        case 's':
        case 'd':
        /*
         * Normally we would do something specific for each one of
         * these 
         */
        printf("The -%c flag\n", argv[i][1]);
        break;
        default:
        printf("\"-%s\" is not a valid one-letter flag\n",
               argv[i][1]);
        return 1;
        }
    } else if (argv[i][0] == '-' && argv[i][1] == '-') {
        /*
         * Get rid of the first 2 characters (both are '-') 
         */
        arg = argv[i] + 2;

        /*
         * Normally we would do some parsing here 
         */
        printf("The --%s flag\n", arg);
    } else {
        /*
         * Everything else we simply treat as a parameter 
         */
        printf("\"%s\" as a parameter\n", argv[i]);
    }
    }
}

Kernighan & Ritchie

This is the style used in Kernighan & Ritchie’s book, “The C Programming Language”. It is also sometimes known as “the one true style”. While that’s a bit over-the-top, it’s a decent starting point.

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    int i;
    char *arg;

    for (i = 0; i < argc; ++i) {
    /* Check to see if it's a one-letter flag */
    if (argv[i][0] == '-' && argv[i][1] != '\0' && argv[i][2] == '\0') {
        switch (argv[i][1]) {
        case 'h':
        /* Help flag */
        printf("This is the program help.");
        return 0;

        case 'n':
        case 's':
        case 'd':
        /* Normally we would do something specific for each one of
         * these */
        printf("The -%c flag\n", argv[i][1]);
        break;
 
        default:
        printf("\"-%s\" is not a valid one-letter flag\n",
               argv[i][1]);
        return 1;
        }
    } else if (argv[i][0] == '-' && argv[i][1] == '-') {
        /* Get rid of the first 2 characters (both are '-') */
        arg = argv[i] + 2;

        /* Normally we would do some parsing here */
        printf("The --%s flag\n", arg);
    } else {
        /* Everything else we simply treat as a parameter */
        printf("\"%s\" as a parameter\n", argv[i]);
    }
    }
}

Linux Kernel Style

This is the style used in the source code for the Linux kernel.

#include <stdlib.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    int i;
    char *arg;

    for (i = 0; i < argc; ++i) {
        /* Check to see if it's a one-letter flag */
        if (argv[i][0] == '-' && argv[i][1] != '\0'
            && argv[i][2] == '\0') {
            switch (argv[i][1]) {
            case 'h':
                /* Help flag */
                printf("This is the program help.");
                return 0;
            case 'n':
            case 's':
            case 'd':
                /* Normally we would do something specific for each one of
                 * these */
                printf("The -%c flag\n", argv[i][1]);
                break;
            default:
                printf
                    ("\"-%s\" is not a valid one-letter flag\n",
                     argv[i][1]);
                return 1;
            }
        } else if (argv[i][0] == '-' && argv[i][1] == '-') {
            /* Get rid of the first 2 characters (both are '-') */
            arg = argv[i] + 2;

            /* Normally we would do some parsing here */
            printf("The --%s flag\n", arg);
        } else {
            /* Everything else we simply treat as a parameter */
            printf("\"%s\" as a parameter\n", argv[i]);
        }
    }
}