int xx = 0;
int yy = xx + 1;
In the above example, the names xx
and yy
are not meaningful but in the following example, the names size
and maxSize
will carry a sense of the corresponding variable's usage in the code. The reader of the code can understand what is going to be stored in the variable just by reading the name of it.
int size = 0;
int maxSize = size + 1;
If you notice rule 1, this will act like an identity card for the function. You can guess the algorithm and behavior of the function to a good extent just by seeing the variables used in the function. So present the identity card in the beginning not in the end. This will increase readability of the code and minimize the risk of redefining a variable and getting compiler errors.
int featureCount()
{
int sum = 0;
int i = 0;
for (i = 0; i < MAX_FEATURES; i++)
sum += getFeatures(i);
}
3- camelCase naming convention: Variable name should start with lowercase letters. In multi-word variables, each word except the first should start with an uppercase.
Notice:
- The rule states naming style
- The rule says not to be afraid of multi-word variables
- The rule recommends not use to special characters (characters which are typed with the help of modifier keys,
Ctrl
,Shift
andAlt
) - Programmers usually use characters like
_
and__
. But it's recommended not to use. Because:- You can type variable name more quickly and will not use to keys to write one character.
- Variable name continuity will be preserved and optical illusion won't cause the reader to see one character as two.
int maxSize; // NOT: int max_size;
int tableCellWidth; // NOT: table_cell_width;
You'll often define several variables which all have the same usage like intermediate or temporary variables. Don't act like this:
int tmp1, tmp2, …;
Try to choose a suitable name:
int tmpSize, tmpCount, ..;
Remember: naming as tmp1, tmp2, …
is like calling the children in a family as child1, child2, …
5- Do not use the suffix s
for variables which present number, instead use the prefix n
or the suffix List
There are two reasons:
- You may not see the
s
by mistake. - Usually there are two variables, one with the suffix
s
and another without it and this will increase the probability of humen error by programmers.
It's recommended to use the suffix List
instead of the prefix n
but after choosing one, you should use the same style till the end of coding for your project.
int featureList; // NOT: int features
int nLine; // NOT: int lines
For example you can use tmp
for a variable in block scope or function scope but not for a variable in class scope. So try length of variable's name be proportional with its scope in order to not be confused while reading the code.
Rule of thumbe: Variable name length is proportional to inverse of its scope.
Avoid using excessively lengthy names for variables. You're sometimes allowed to use acronyms and summarize the name based on the variable scope. For example in a small function scope, you may be able to use stuID
to store students's identity number but sometimes you'll have to write studentID
.
The important rule is: Do not make the code so lengthy by lengthy variable names and also do not make the code confusing by excessively short and summarized variable names.
In some standards, it is recommended to stick the character *
to variable type but there are disadvantages with this recommendation.
- The reader may not see
*
while reading the code and not notice that the variable is a pointer. - It is often recommended to define a new variable with
typedef
for pointers. In fact sticking*
to datatype is like defining a new type not naming a variable of pointer type.
RGFeature *feature = NULL, centerFeature; // NOT: RGFeature* feature = NULL, centerFeature;
Also it is emphasized in all C++ books that in examples like the above code, just feature
is a pointer notcenterFeature
. If you stick *
to datatype, this will not be evident in the code.
In order to increase readability and recognize class variables easily while reading the code, class variable names should start with the prefix m
. It is clear that rule 3 should also be considered and name of variable coming after prefix m
should start with a capital letter.
class RGFeature
{
privet:
int mSize; // NOT: int size_; int _size; int m_size; int msize;
}
10- Name loop counters as i
, j
, k
and if there are more than 3 nested loops, use l
, m
, n
for naming inner loop counters
This has been common among programmers so we try to obey good prevalent rules. Also loop scope is the smallest among block scopes and the rule is consistent with rule 6 and rule 7.
The proper prefix is the acronym of company name. Naming in this style will be a way to express the owner of the code. Using capital letters will result to quick discrimination between variable and its type.
class RGFeature
{
…
};
//NOT: class rgFeature …
//NOT: class RgFeature …
Using capital letters will result to quick discrimination between macros and other variables and types. Using _
will also quicken recognition of macros because it is not used in any other case.
#define MAX_SIZE 5
//NOT: #define MAXSIZE 5
//NOT: #define maxSize 5
//NOT: #define max_size 5
13- Function names should start with lowercases just like rule 3 and should express the task of the function
In C
programming language, functions are actually variables of pointer type so regarding this, naming functions just like variables is acceptable. In addition function and variable are the same concept in programming.
The important point in function names is that they should be meaningful. It is necessary to recognize the task of a function just by it's name. That will be really helpful in reverse engineering of the code.
For example suppose a function which its task is to calculate the average of an array. The name average
would not be suitable because it doesn't imply the concept of calculating and it seems that the function just reads the average value and returns it. Naming this function as calcAverage
or computAverage
would be more suitable. So consider the following recommendations when naming functions:
1- Functions which read or write class variables should be named as set[var]()
or get[var]()
2- Functions which are used for searching should have the prefix find
like findMax
or findNearestFeature()
3- Functions which are used for initialization should have the prefix init
or initialize
like initDistance()
4- Functions which return boolean
variables should have the prefix is
like isEnabled
or isActive
5- Sometimes can
, has
, should
will be used instead of is
in case 4
One of the important points in writing code is that it should be clear. So delete the codes that you have commented right after getting sure that one piece of code is working correctly.
If you have created extra outputs by printf
while debugging, delete them right after getting sure that a piece of code is working correctly.
For example consider the following pieces of code, the second one is much easier to debug, read and track than the first.
int scnNum = 0;
int i;
// QStringList clientNames;
QStringList clientIP;
/* RGSceen *scn;
QHBoxLayout *layout = NULL;
setupUi(this);
mConfig = config;
*/
mConfig->get("screen", "name", clientNames);
mConfig->get("screen", "ip", clientIP);
scnNum = clientNames.size();
// if (scnNum == 0 || scnNum != clientIP.size ())
QMessageBox::critical(this, tr("Client Ui"), tr("Invalid screen definition!"));
// else
{
layout = new QHBoxLayout(this);
for (i = 0; i < scnNum; i++)
{
/* scn = new RGSceen (this, clientIP.at (i));
scn->pushButton->setText (clientNames.at (i)); */
layout->addWidget(scn);
}
int scnNum = 0;
int i;
QStringList clientNames;
QStringList clientIP;
RGSceen *scn;
QHBoxLayout *layout = NULL;
setupUi(this);
mConfig = config;
mConfig->get("screen", "name", clientNames);
mConfig->get("screen", "ip", clientIP);
scnNum = clientNames.size();
if (scnNum == 0 || scnNum != clientIP.size())
QMessageBox::critical(this, tr("Client Ui"), tr("Invalid screen definition!"));
else
{
layout = new QHBoxLayout(this);
for (i = 0; i < scnNum; i++)
{
scn = new RGSceen(this, clientIP.at(i));
scn->pushButton->setText(clientNames.at(i));
layout->addWidget(scn);
}
}
While reading a code, jumping to the next line is time-consuming. The reader also may neglect a line due to optical illusion. So do not break the lines unnecessarily in order to not violate rule 14
int findMax (QStringList stringList, int startIndex);
// NOT:
int
findMax (
QStringList stringList,
int startIndex);
But if the line is so lengthy, in a way that you should use horizontal scrollbar, then break the line based on the following rules.
1- Each function parameter should be in a seperate line with the comma (,
) at the end of the line.
2- Operators should always be at the end of the line.
int findMax (
QStringList stringList,
int startIndex);
// NOT:
int findMax (
QStringList stringList, int startIndex);
x = ( a + b +
c + d );
// NOT:
x = ( a + b
+ c + d );
Programmers often encounter variables which take a limited number of values. They may take a value for each case in their mind and pass these values to functions or use them in conditional (if
) statements instead of cases. For example:
if ( type == 1)
getSize (type, 2);
But there are disadvantages with this approach.
1- The code is not beautiful
2- The code is obscure.
3- Tracking the code for debugging or reverse engineering is so hard.
So use macros instead of numbers.
#define SURFACE 1
#define AIR 2
#define SUBSURFACE 3
..
..
if (type == AIR)
getSize (type, SURFACE);
Sometimes it is recommended in C++ books to use enum
s in such circumstances. But we would not recommend. Because
1- Usind enum
s will increase compilation time.
2- Compilers produce lots of errors for cast
s and enum
s.
3- Lots of types will make tracking the code so hard.
Always use white space in the following cases:
1- Before and after operatoros a = b + c \\NOT a=b+c
2- After comma in function parameter lists hanoi (a, b, c) \\NOT hanoi(a,b,c)
3- After ;
in loops for (i = 0; i < n; i++) \\NOT for (i = 0;i < n;i++)
4- Before (
and after )
a + b (c) d \\NOT a + b(c)d
5- Between name of the function and (
which comes after it hanoi (a, b, c) \\NOT hanoi(a, b, c)
6- Between keyword and parenthesis hanoi ( int a, int b, int c) \\NOT hanoi (int a, int b, int c)
7- Alignment is very important so use white spaces to keep the code aligned
For example look at the following piece of code:
int findMaxArea(int sizeList[], int count)
{
int i;
float area = 0.0, maxArea = 0.0;
for (i = 0; i < (count - 1); i++)
{
area = sizeList[i] * sizeList[i + 1];
if (maxArea < area)
{
maxArae = area;
}
}
return maxArae;
}
As you see while defining variables, we've tried to use white space in order to i
and area
be aligned.
The law is to avoid overdoing and underdoing. Meaning that you should use white spaces in a way that your code becomes beautidul, easy to track and retains readability. So do not be constrained to rule 17 but also do not violate it completely
Remember that functions are not going to be a complete program. Functions are used for abstraction and prevent renewed coding. So if there is a function with several thousands lines of code in your project, it means that the function is a complete program itself which can be divided into several other functions.
So if there is such function in your project, there's probably a big mistake in the design and implementation and the project should be reviewed. Notice that here by lines of code, we don't mean whitespace or empty lines which are created for readability. The best way to understand whether the function is long or not, is to implement not more than one or two algorithms in a function.
Programmers sometimes use commands like this to shorten the project:
a = ((x = sin ( getAngle (feature) / 2.0)) > VALID_SIZE ? 2*x:x);
These commands are hard to understand even for the programmers themselves and it's better to break them down to several other commands.
angle = getAngle (feature) / 2.0;
y = sin (angle);
if (y > VALID_SIZE)
a = 2 * x;
else
a = x;
// OR:
a = x;
angle = getAngle (feature) / 2.0;
y = sin (angle);
if (y > VALID_SIZE)
a = 2 * x;
Obviously the latter code is much easier to understand and debug.
Avoid writing #include
s in an irregular manner because it will cause errors in unexpected places. For example consider the following code:
/// sample.h
#ifndef RG_SAMPLE_H
#define RG_SAMPLE_H
class RGSample
{
…
}
#endif
///sample.cpp
#include "sample.h"
#include "stdio.h"
…
When compiling this code, the compiler will show you an error inside stdio.h
. But why?
Since there is no ;
after class definition, the compiler reads the code until reaching the next ;
and declares an error in this point. Since the next ;
is inside stdio.h
, the error will be declared inside stdio.h
but in fact the error is in sample.h
. This can make programmers confused.
So it is recommended to categorize header files and to place an empty line between each category. Also order them based on accuracy. So obviously system header files
will be placed on the top and program header files
on the bottom.
#include system header file
#include external library header file
#include library header file
#include program header file
For example:
#include <stdio.h>
#include <stdlib.h>
#include <QWidget>
#include <QObject>
#include <geos.h>
#include <ogr.h>
#include "sample.h"
There are disadvantages with placing #include
s in header files.
1- Since header files are inserted in source files, inserting them to header files will lead to violation of rule 20
2- The probability of compiler errors gets higher
3- The probability of adding unnecessary header files will be higher which will create unnecessary dependency and increase compile time
Of course there are exceptions
1- In 3rd party libraries, there is a header file which all other header files are placed inside it
2- Sometimes a class is consisted of several files but for the sake of easier management, a .h
and a .cpp
file is created for the class in which all the other header files and source files are written
For two reasons
1- since the header file is inserted in various source files, any problem in the implementation will lead to a lot of compiler errors
2- Sometimes header files should be released but not the implementation
Consider the following code:
max = ( y > x ? y:x); // find max value
Even someone with zero programming knowledge can understand the purpose of this line without any explaination and comment.