-
Notifications
You must be signed in to change notification settings - Fork 0
C and C++ coding conventions
cjfrisz edited this page Sep 23, 2011
·
8 revisions
I've seen as many styles for C as many times I've been on C-based projects. I've picked up a lot of conventions from different people and experimenting with what I find most readable after I'm away from the code for a few days. I've also probably spent as long thinking up the best way to write code as I have on interface design, so most of these aren't arbitrary in the slightest.
There are a lot of guidelines that relate specifically to C++, but the overlap of the two languages makes it silly to present them separately. However, I will try to indicate when possible if a convention applies to a specific language.
- Lines are absolutely no longer than 72 characters. Where applicable I will try to provide strategies for splitting lines should you run over the limit.
- NOTE: I've often heard this guideline because it's the width of a normal letter-sized page with reasonable margins. Additionally for myself, I often code on a 10.2" netbook screen (because I'm a crazy person) and 72 characters is exactly the width of a vertically split emacs buffer on my screen.
- Use camel-case for file, class, function, variable names, and most anything else that needs naming. The only time that I don't use camel-case is for constant values, for which I use all caps with underscores separating words/tokens.
- NOTE: I know that camel-case isn't as readable as underscores, but camel-case is much easier to type.
- For dates, Use the numerical date, a three to four word abbreviation for the month, and the year
- Example: 17 Sept 2011
- Tab characters are evil. Instead use 4 spaces. Generally any good text editor can be set to insert 4 spaces when pressing the tab key.
- Header (aka interface) and implementation files should be separated. The only exception is in C++ when using template classes. Of course this is a restriction of most compilers since generally type variables have to be initialized all at once across the class declaration and definition.
- Header files should have a '.h' file extension for both C and C++.
- There is a '.hpp' extension for C++ header files, but many big projects use '.h' anyway, including Google. Just as a side note, Google has a very extensive C++ style guide themselves from which I picked up some conventions myself.
- Implementation files ('.c' or '.cpp') should match the name of the associated header.
- This is pretty standard, but it bears mentioning.
- For library-style modules, use a camel-case name starting with a lower-case letter. Try to use a descriptive name for the library.
- For C++ classes, name both the header and implementation file after the class it defines using camel-case starting with a capital letter.
- All files need to have a header (following the license, if applicable) that consists of the following parts:
- File name
- Project name
- Author(s) and email address in parentheses
- For multiple authors, list each one on a new line starting after "Written by" line. Indent four spaces (no tab characters) from the "Written by" line.
- Should an author line exceed the 72 character limit, put the email address on its own line indented an additional four spaces.
- Organization information, if applicable
- For school projects, I include my school (Indiana University), course name and/or catalog number, and semester
- Creation date and responsible author
- Date of last update and responsible author
- Short description of the file's purpose
- Headers are written using the block comment style (
/* ... */), with the first line consisting of the opening forward slash (/) and 70 asterisk (*) characters, followed by the appropriate information (described above) with each line starting with a space, one asterisk (*), and another space. Similar to the opening line, the last line of the header consists of 70 asterisks (*) and the closing forward slash (/). - An example header:
/********************************************************************** * example.h * Example project * Written by Chris Frisz (cjfrisz@chrisfrisz.com) * Friszy Productions, Inc. * Created 17 Sept 2011 by Chris Frisz * Last updated 17 Sept 2011 by Chris Frisz * * Defines the interface for the example library. If there was * anything interesting to explain about the library in general, I * would put it here. **********************************************************************/
NOTE: Sorry about the formatting, this is a known issue with GitHub
- Always use include guards for interface files. The symbol passed to
#ifndefand#defineshould be the name of the file with the period replaced with an underscore. Additionally, the symbol should be prepended and appended with a double underscore (__). For example (assuming the interface file example.h):
#ifndef __EXAMPLE_H__ #define __EXAMPLE_H__ [ Whatever code appears in the interface ] #endifAgain, sorry about the formatting
- Function declarations should be written on one line and follow this form:
int functionName (char funcArg1, int funcArg2);
- Note that there is a space between the return type, function name, and argument list. There is also a space between each argument after the comma.
- Should a function declaration exceed 72 characters, start adding line breaks from left to right. That is, first put one after the return type, then the function name, then the argument list. Should it still exceed the maximum length, start breaking the argument list after each comma.
- Provide names for all arguments in the function declaration.
- Each function declaration is preceded by a block comment including the following information:
- Function name
- Return type
- Each argument (name and type) and a short description of what it represents as well as any restriction
- A short description of what the function does, including a high-level description of how the inputs are used to produce the outputs.
- Function header blocks should follow this form:
/* * Function: * functionName * Type: * int * Arg char funcArg1: * The first function argument. * Arg int funcArg2: * The second function argument. * * Takes funcArg1 and funcArg2 and generates an int by doing some work on them. */
- There should only be one class defined per file.
- Use forward class declarations when only referencing classes (i.e. using a class as a member variable)
- A class file must be included if referencing a member function (which would be weird in a class definition) or if inheriting that class
- This prevents compilation errors when classes reference each other.
- I.e. Class1 includes a member variable of type Class2 and vice versa.
- Class members should be organized by public, protected, and private access.
- Within each access classification first list variables then functions.
- An explicit constructor, destructor, and copy constructor should all be declared and have public access.
- Explicitly defining the destructor, copy constructor, and assignment operator is often a useful exercise for the class programmer to consider which variables need to be destroyed and how to copy information from one instance of a class to another.
- In general, I believe in never trusting the compiler for automatically-generated code to govern behavior of user-defined objects.
- Only one default constructor should be provided that takes no arguments unless absolutely necessary
- Overloading the constructor can be convenient for programmers using the class, but expands code size and often reduces readability of the code. Additionally, constructors with parameters should be equivalent to initializing an instance of the class with default values and then using accessors to set its specific values. This is why I believe in explicit class composition over myriad constructors for each set of possible arguments. That is, additional constructors don't add functionality, and while less convenient, make the programmer be explicit in defining each instance of a class.
- An overridden assignment operator (
=) should also be declared with public access. - In addition, a protected function with the name of the class prepended with the word "copy" should be declared.
- i.e. for class ExampleClass, it would be named copyExampleClass
- This function can be used to do the interesting copy work of the copy constructor and assignment.
- This way all copy constructors can be of the form:
ExampleClass ExampleClass::ExampleClass (const ExampleClass &original) {
this->copyExampleClass(original);
}
- Similarly the assignment operator can be of the form:
return *this; }
- All member variables should be made private.
- Public accessors should be provided for access to primitive member variables.
- Observers should have the same name as the associated member variable prepended with "get"
- Mutators should have the same name as the associated member variable prepended with "set"
- For complex, non-primitive member variables (e.g. vectors, maps, etc.), provide public methods to perform actions appropriate for the variable with respect to the class.
- Vague, I know
- Use pointers for non-primitive data types (e.g. containers like vectors, classes, etc.)
- Functions should be preceded by header blocks as described for Interfaces
Back to Coding conventions