Every project has its own style guide: a set of conventions about how to write code for that project. Some managers choose basic coding rules, others prefer very advanced ones, and for many projects no coding rules are specified at all — each developer uses his own style.
It is much easier to understand a large code base when all the code in it is written in a consistent style.
Many resources exist about the best coding rules to adopt; we can learn good coding rules from:
- Reading a book or a magazine.
- Websites.
- From a colleague.
- Taking a training course.
We can also work with an expert for a few months to improve the coding skills of the team. However, it’s not easy to find the right person, and it can cost the company a lot of money. But why search for an expert when we can be inspired by genius developers like Linus Torvalds? Indeed, you just have to explore the source code developed or maintained by him to get a good idea of how to write efficient C code.
Linus Torvalds is a genius because he’s the creator — and for a long time the principal developer — of the Linux kernel, and he also created the most popular distributed revision control system, Git. That’s it — no need to look for other arguments :)
Inside the Git source code
Let’s take a look at a code snippet from Git:

Here are some remarks about this code:
- The functions are declared static.
- The functions return an error code.
- The function has few parameters.
- The function exits as early as possible.
- The variables are declared static.
- The variable naming is easy to understand.
- The functions are very short.
- It’s well indented.
- No extra comments in the body: the code speaks for itself.
- The function bodies are well indented.
- The define guards are clear.
If we navigate across the whole Git source code, we can notice the consistency of the implementation: the same best-practice rules are applied to every function. To be sure, let’s search for the static functions:
from m in Methods where m.IsStatic select m
The treemap is very useful for getting a good idea of the code elements concerned by a CQLinq query; the blue rectangles represent the result.

Almost all functions are declared static, so they are visible only in the translation unit where they are declared.
Inside the Linux kernel source code
Let’s switch to the Linux source code and take as an example this function implementation:

The code looks very clean; indeed, the function
- has only a few lines of code.
- The signature is well defined.
- It’s well commented.
- It’s well indented.
- The variable names are very clear.
- const correctness is respected.
- It checks the input parameters and warns if they don’t satisfy some conditions.
The same function could be implemented by another developer like this

Coding style has a big impact on source code readability; investing a few hours in training developers and doing periodic code reviews is always good for making the code easy to maintain and evolve.
Let’s go inside the Linux kernel source code using CppDepend and discover some basic coding rules adopted by its developers.
Modularity
Modularity is a software design technique that increases the extent to which software is composed of separate parts; modular code is easier to manage and maintain.
For a procedural language like C, where no logical artifacts like namespaces, components or classes exist, we can modularize by using directories and files.
Here are some possible scenarios:
- Put all the source files in one directory.
- Isolate files related to a module or a submodule into a specific directory.
In the case of the Linux kernel, directories and subdirectories are used to modularize the kernel source code.
EncapsulationEncapsulation is the hiding of functions and data which are internal to an implementation. In C, encapsulation is performed by using the keyword static. These entities are called file-scope functions and variables.
Let’s search for all static functions by executing the following CQLinq query:

We can use the Metric view to get a good idea of how many functions are concerned. In the Metric View, the code base is represented by a treemap. Treemapping is a method for displaying tree-structured data by using nested rectangles. The tree structure used in a CppDepend treemap is the usual code hierarchy:
- Projects contain directories.
- Directories contain files.
- Files contain structs, functions and variables.
The treemap view provides a useful way to represent the result of a CQLinq query, so we can visually see the types concerned by the query.

As we can see, many functions are declared static.
Let’s search now for the static fields:

The same remark as for functions: many variables are declared static.
In the Linux kernel source code, encapsulation is used whenever functions and variables must be private to the file scope.
Use structs to store your data model
In C programming, functions use variables to perform their processing; these variables can be:
- Static variables.
- Global variables.
- Local variables
- Variables from structs.
Each project has its data model, which can be used by many source files. Using global variables is a solution, but not a good one; using structs to group data is more recommended.
Let’s search for global variables with a primitive type:

Only very few variables are concerned, and maybe we could group some of them into structs, like (elfcorehdr_addr and elfcorehdr_size) or (pm_freezing and pm_nosig_freezing).
Keep functions short and sweet
Here’s some advice about the length of functions from the Linux coding style web page:
Functions should be short and sweet, and do just one thing. They should
fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,
as we all know), and do one thing and do that well.
The maximum length of a function is inversely proportional to the
complexity and indentation level of that function. So, if you have a
conceptually simple function that is just one long (but simple)
case-statement, where you have to do lots of small things for a lot of
different cases, it's OK to have a longer function.Let’s search for functions with more than 30 lines of code.

Only a few methods have more than 30 lines of code.
Function number of parameters
Functions where NbParameters > 8 might be painful to call and might degrade performance. Another alternative is to provide a structure dedicated to handling arguments passing.

Only 2 functions have more than 8 parameters.
Number of local variables
Methods, where NbVariables is higher than 8, are hard to understand and maintain. Methods, where NbVariables is higher than 15, are extremely complex and should be split into smaller methods (except if they are automatically generated by a tool).

Only 5 functions have more than 15 local variables.
Avoid defining complex functions
Many metrics exist to detect complex functions; NBLinesOfCode, number of parameters and number of local variables are the basic ones.
There are other interesting metrics to detect complex functions:
- Cyclomatic complexity is a popular procedural software metric equal to the number of decisions that can be taken in a procedure.
- Nesting Depth is a metric defined on methods, relative to the maximum depth of the most nested scope in a method body.
- Max Nested Loops equals the maximum level of loop nesting in a function.
The maximum value tolerated for these metrics depends mostly on the team’s choices; there are no standard values.
Let’s search for functions that are candidates for refactoring:

Only very few functions could be considered complex.
Naming convention
There’s no standard naming convention; each project manager can choose what he thinks is best. However, what’s very important is to stick to the chosen convention to have homogeneous naming.
In the case of Linux, structs must begin with a lowercase letter, and we can check if that’s true for the whole kernel source code — let’s execute the following query:

Only 4 structs begin with “_” instead of a lowercase letter.
Indentation
Indentation is very useful for making code easy to read; here are the motivations behind it from the Linux coding style web page:
Rationale: The whole idea behind indentation is to clearly define where
a block of control starts and ends. Especially when you've been looking
at your screen for 20 straight hours, you'll find it a lot easier to see
how the indentation works if you have large indentations.
Now, some people will claim that having 8-character indentations makes
the code move too far to the right, and makes it hard to read on a
80-character terminal screen. The answer to that is that if you need
more than 3 levels of indentation, you're screwed anyway, and should fix
your program. ConclusionExploring well-known open source projects is always good for improving your programming skills, especially if they are developed and maintained by experts. No need to download and build the project — you can just browse the code on GitHub.
