Page 1 of 1

The not so comprehensive but still good guide to C style Rate Topic: -----

#1 stackoverflow  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 164
  • View blog
  • Posts: 545
  • Joined: 06-July 11

Posted 10 July 2011 - 10:04 AM

The not so comprehensive but still good guide to C style


This is not a comprehensive style guide. This is an introduction to good style practices. To be more specific this is a guide surrounding my style. I have adopted a number of different style choices. My style may not be perfect and there may be other good style practices.This is not meant to be a complete guide but rather a starting place for beginners.

For a complete style guide you may find the book Code Complete very useful. It is a well-known book and held in high regard. Style practices are generic and may apply to any number of languages. I am going to use C as the target of this tutorial. However, you may very well apply your own version of this to C++, Java or any other language in the C family.

Note:
Object Oriented programming languages typically involve a number of extra style characteristics which range in complexity. Many of these styles revolve around uses of polymorphism, inheritance and other complex topics. This guide is for C and will avoid complex topics. Typically, if you want to delve into those style guidelines the best place to start is a good book like CC listed above. Another good book recommendation are the "effective" book series. Effective C++, Effective Java, etc. These books are advanced and dive into managing complexity and good style.


Disclaimer:
These are my own style choices. If you feel you have a better style choice or alternative then by all means discuss it. The more discussion we have on style the more opportunities learners will have to pick up good practices. The placement of this guide was chosen to be outside of the C++ basics forum because this guide assumes the user has a basic understanding of programming.

Introduction

Let's begin by driving home a point about style. The point is, "Any style is better than no style." Let's look at a horribly formatted function:

     int ReturnthesumoftheNumbers(int one, int two){
int m;
  m = one + two;
    return m;     
}



Now let's look at the same code with a little style:

int sum(int one, int two)
{
	return one+two;     
}



I think we can all agree the version with a little style is much easier on the eyes. Furthermore it's easier to follow. This is why we must study style and pick up good habits. Even if a programmer does not agree with the choices I made for style-- they will agree a style is better than none.

The remainder of this tutorial will include an outline of my C style regarding comments, braces, naming, and general advice. Remember these are my style choices and they are not set in stone. Learning style is like learning to be fluent in a language. Once you are fluent and understand the 'good' structure you also learn when you are allowed to break the structure. There are going to always be exceptions to the rules and that is why these are not set in stone. However, following these will rules will keep your code sane until you learn when to break the rules.

Comments

We begin with a discussion of comments. In C there are two kinds of comments the // and the /* */ kind. I assume you all know them already if you are reading this guide. What you may not know is // were actually added to plain C after the invention of C++. Therefore old C code and compilers are not compatible with // comments. For that reason we will always use /* */ comments in C.

There are a number of common places to place a comment in a program. The first location is at the very top of the source file. The comment at the top should list the name of the source file, the author(s) of the source file, the description of the program and/or the source file, and finally the copyright information. You don't need to list all of this information in every program-- but it's interesting to note that in large projects or professional code it is a good idea to add them. Furthermore, if you are a student it's a good idea to comment at the top and list information shown above as well as your student id and/or class information.

Another common area to place a comment in C is above the function declaration and not above the definition.The declaration is the portion that belongs in a header file. I follow a specific pattern when I comment my function declarations. I always start with the name of the function and a description, then a list of the arguments and what they are, followed by the expected return type and any oddities the function may throw.

Example:
/**
* sum - adds two numbers together
* @one: the first number we wish to add
* @two: the second number we wish to add 
* @return: returns the sum of arguments @one and @two in integer format
**/
int sum(int one, int two);



That may seem like overkill for such a simple function-- but style is about consistency. If you are using a style throughout an entire program it will disrupt the flow if you change your style. I follow this style of comment for all of my function declarations. It is clear and concise. All the information we need to know is right there.

Another common use for comments is in the middle of code. Typically code is done in the source files and not in the header files. These comments should be clear and concise as well. The comments should flow with the code and not disrupt it in any way. Furthermore, the comments should not state the obvious. Remember that good code should not need a comment because it is clear. Only code that is unclear needs a comment. Imagine the code being read from a third party. Better yet, imagine a high school student that has never programmer in their entire life trying to understand your code. If they can not make sense of a section of it then it probably deserves a comment.

BAD Example:

int sum(int one, int two)
{
	return one + two; /* this returns the sum of one and two */
}



First off we explained in the declaration what the function does and returns. So we are not only repeating ourselves we are stating the obvious. Even an elementary school student can look at one plus two and figure out what is going on.

Better Example:

int sum(int one, int two)
{
	/* NYI: error checking for invalid input */
	return one + two;
}



This is a bit better. In case you don't know NYI is an acronym that means Not Yet Implemented. We didn't check if the user as input characters or weird input. At least this comment gives us something useful. It still isn't perfect because this kind of problem should have been discussed during the declaration, but at least the problem has been discovered and noted so it can be implemented.

Note:
kiwi_steve has brought it to my attention an alternative to NYI is, TODO: which if used in an IDE like Eclipse will flag that comment and help it stand out as an area that needs attention.

That concludes the basics of commenting. To wrap it up-- don't state the obvious and be consistent.

Braces

Braces are the code block delimiters. Generally we can play fast and loose with these little guys-- but I like to be consistent with my style. I have adopted a few strategies in C.

The first strategy is braces for function declarations different from in-code braces. How do they differ? Well in-code statements can be on a single line but functions can't. Therefore I have adopted the strategy of places the leading brace on a new line after a function signature but in-code braces I place the brace on the same line.

Example:

int power(int base, int power)
{                                   /* Notice brace on new line? */
	int product = 1;
	
	while (product--){              /* Notice brace on same line? */
		product *= base;
	}

	return product;
}



The only other concern with braces is with control structures. As we all know if a control structure has only one statement we can not use braces and the meaning is still the same.

Example:
int power(int base, int power)
{
	int product = 1;
	
	while (product--)
		product *= base;

	return product;
}



Some people think this is confusing and they choose to always use braces. I find always using braces to be a clear and wise choice. If you choose not to that is okay too. Just remember to be consistent. If you don't use them in the project then do not suddenly start using them. If you do use them in that manner then always use them in that manner. Remember it isn't a style if you keep changing it up.

Finally, we should discuss spacing here. You can choose tabs or spaces. This is similar to braces on control structures. If you use tabs then always use tabs. If you use spaces then always use spaces. I enjoy using tabs because it is quicker and less keys for me to hit. Plus the space gained from a tab is large and it is very easy to tell code blocks apart. You should always use the same spaces. If you use spaces then always use the same number of spaces per-block. Don't use 2 spaced blocks and then later use 4 spaced blocks. Again, it isn't a style if you change it up-- it's only confusing.

In addition to code block spacing I would like to add some thoughts on spacing within lines and around operators. For single operators like the math operators, '+', '-', '*' etc, it's preffered to add a single space on the left and the right side. So, they would look like this in use:

if (a * B)/>


Adding spaces increases readability. You may also notice a space after if and before the opening parenthesis. I also like to add a space there for clarity. That means on control structures such as, if, while, for, etc.

Naming

This is another straight forward topic. Names for variables should be chosen carefully. I don't think I need to discuss meaningful variable names. We are all grown-up and I don't think I need to explain why this is just silly:

int function(int sad, int bear){
	return sad+bear;
}



Let's just cut to the point and say choose a name for a variable that expresses what it is or does. A more interesting topic concerning variables is the casing. I have adopted camel casing. In case you don't know, here's an example:

int getSum(int firstNum, int secondNum)
{
	return firstNum+secondNum;
}



Basically the first letter is lower case and then all following letters are upper case. I use this for function names and variable names. I like this style because if you have a single noun or simple variable (or function) it is simply lower case. If you have a more complex variable or function it is clearly wrote out with multiple words. As long as you are consistent it is also easy to remember your names.

I don't like to use underscores because let's face it-- the button isn't too close on the keyboard and going out of the way just wastes time and energy. I don't keep all characters lower case because that would be hard to read. In addition to camel casing I like to apply a simple style to how I name functions. Functions are generally actions and thus using verbs is generally a good idea. That is why I used "get" followed by what the function gets, the "Sum." Therefore, "getSum" is very easy to understand. We can look at the name and know it's a function and we even have an idea of what it does and returns. That's a descriptive name. Variable names don't generally use verbs because variables are often noun-like. Therefore I use nouns for them and I try to keep them singular and not plural. If a variable will be used to count the number of cars I would rather call it "carCount" than "cars" because carCount is more descriptive. Although it is longer it has more meaning and makes the code easier to follow.

General Advice

Finally-- we have a basis of style! What now? Well, we can have the greatest style and it wouldn't matter if we did odd things in the programming language. Generally we have a few rules of thumb to follow:

* Avoid goto statements. They are confusing and complicate things. If you find yourself using a goto statement you are probably doing something wrong.

* Write short functions. You should try to limit your function length to a single page. The longer your functions are the more likely you are to make mistakes. If all of your code isn't visible then you are more likely to forget portions of it. If you find yourself writing a long function then you probably need to chop the large function up into smaller functions. Find smaller routines that are used often and turn them into small functions. Generally, a function should do a single task. If a function is doing more than one task then it is more like a small program within a program!

* Line length should be limited. The rule of thumb is 80 characters per line (cpl). This is an old school limit that is considered the norm. Old code uses this limit because back in the day people only had 80cpl terminals to program with. As time goes on we still find 80cpl to be a good limit. Limiting the line length forces you to think of each line and write better code. Instead of hammering out large lines that do a lot you are forced to think about it more and make it clear and concise. In an object oriented language you may need a bit more space. I find 100cpl to be more common in C++.

Interesting read on cpl.

* Limit scope. You should attempt to limit the scope of variables. If you find yourself declaring a large number of variables outside of main because you need the global scope-- you are most likely not designing the program in an efficient manner. You may need to review pointers, or read about encapsulation and data hiding."

* Don't use excessive nesting of loops. If you need more than 3 nested loops then you are probably doing something wrong. That generally means it is time to hit the paper and design a better program.

* Return values are useful. Using return values to determine status and fix problems is very useful. Furthermore, I would like to say EXIT_SUCCSESS and EXIT_FAILURE should be used when returning from main and or when you make a call to exit(). Other wise you should use a meaningful return value. Generally, -1, NULL or 1 mean failure and 0 means success.

* Don't use magic numbers. If you want to use a special meaning by all means use a define statement. For example, return(IOERROR) has a lot more meaning than return(6789).

* Don't use void main. Just don't.

* If a function definition takes no arguments then say void! This applies to C and not C++. In C++ if a function has no arguments then the compiler knows it is void. However, that isn't the case in C. For example, displayResults() is not the same as displayResults(void). In the first case a user can insert arguments but they can not in the second case.

Well that's all for now folks. I hope you enjoyed reading and I hope this has helped someone. I would like to conclude with a small program that demonstrates some of my style.

/*
*Name        : stackscstyle.c
*Author      : StackOverflow
*Version     : 1.0
*Copyright   : GNU GPL
*Description : A simple program to display a simple style.
*/

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

/*
 * welcomeUser - displays a welcome message and initializes the random seed
 * @return: void
 */
void welcomeUser(void);

/*
 * getRandomNumber - gets a random number between @base and @limit
 * @base: the lowest possible value
 * @limit: the largest possible value
 * @return: a number between @base and @limit in integer format
 *
 * NYI: error checks
 */
int getRandomNumber(int base, int limit);

int main(void) {
	welcomeUser();

	if (getRandomNumber(0, 100) == 100){
		printf("..Wow, you are lucky!\n");
	} else {
		printf("..looks like lady luck isn't on your side today.\n");
	}
	
	return EXIT_SUCCESS;
}

void welcomeUser(void)
{
	srand(time(NULL));
	printf("Hello and welcome,\n\nLet's see how lucky you are..");
}

int getRandomNumber(int base, int limit)
{
	return rand() % (limit - base + 1) + base;
}


This post has been edited by stackoverflow: 13 July 2011 - 06:55 AM


Is This A Good Question/Topic? 2
  • +

Replies To: The not so comprehensive but still good guide to C style

#2 kiwi_steve  Icon User is offline

  • D.I.C Head

Reputation: 31
  • View blog
  • Posts: 109
  • Joined: 26-September 09

Posted 13 July 2011 - 04:24 AM

This is a great tutorial. A couple of comments from my experience tho:

In Eclipse, a comment (talking Java here) that starts //TODO: will get flagged and cause a wee blue marker to appear beside the code. Its an alternative to NYI that works well for those coding in Eclipse, as the visual cue is a great reminder.

And when operating on two variables, spaces either side of the operator makes the code easier to read (ie: one + two rather than one+two)

Cheers for writing this up - I'm sure it will be helpful to a lot of people

Steve
Was This Post Helpful? 1
  • +
  • -

#3 stackoverflow  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 164
  • View blog
  • Posts: 545
  • Joined: 06-July 11

Posted 13 July 2011 - 06:49 AM

View Postkiwi_steve, on 13 July 2011 - 11:24 AM, said:

This is a great tutorial. A couple of comments from my experience tho:

In Eclipse, a comment (talking Java here) that starts //TODO: will get flagged and cause a wee blue marker to appear beside the code. Its an alternative to NYI that works well for those coding in Eclipse, as the visual cue is a great reminder.

And when operating on two variables, spaces either side of the operator makes the code easier to read (ie: one + two rather than one+two)

Cheers for writing this up - I'm sure it will be helpful to a lot of people

Steve


Thanks-- I agree about the spaces. I generally add one space on both sides of all single operators, +, -, *, etc. I also add them for some double operators like, ==, || etc.

I didn't know that about eclipse. That's pretty clever.

I also find adding spaces before the parenthesis in control structures to be nice too. For example,
if (men == human)


Is a little nicer on the eyes than,
if(men == human)


I edited the main tutorial and added your name plus the TODO note in there! I also added a little about spacing as well-- thanks!

This post has been edited by stackoverflow: 13 July 2011 - 06:57 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1