RidgeRun Developer Manual - Coding Styles - C (Linux Kernel)

From RidgeRun Developer Wiki





Previous: Coding Styles/C Index Next: Coding Styles/C++




Introduction to 'C' Linux Kernel Coding Style

When writing software source code there are many coding styles as the concept covers a lot of aspects (some of them subjective). Here we summarize some of the most common concepts, in case of doubt and for more information, please refer to Linux kernel Coding Style Guide.

This guide is similar to C code style for applications, but there are some differences.

Good Practices

Here are some good practices that are applied to C code.

Indentation

  • On Linux Kernel code style, use only 8-character TABS. Do not use spaces to indent.
Note
The Kernel directory contains the scripts/Lindent script that you can use, just make sure to install indent using apt command.

Comments

  • Always use /* ANSI-C style comments */
  • Avoid inline comments:

Yes:

/* This is a comment */
if ( NULL == var ) {
	/* Do something */
}

No:

if ( NULL == var ) { /* This is a comment */
	/* Do something */
}
  • For long comments (multi-line):
/*
 * This is the preferred style for multi-line
 * comments in the Linux kernel source code.
 * Please use it consistently.
 *
 * Description:  A column of asterisks on the left side,
 * with beginning and ending almost-blank lines.
 */

Use a license and authors header

All software need some sort of license and authors documentation, for instance:

/*
 * Copyright (C) 2020 RidgeRun, LLC (http://www.ridgerun.com) 
 * All Rights Reserved.
 * Authors: Name Lastname <myemail@something.com>
 *          Name Lastmane <otheremail@something.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

Naming

  • Local variable names should be short, and to the point. For example, use i for a loop counter.
  • Avoid using variable names like ThisVariableIsATemporaryCounter, instead use tmp or a simple name easy to understand and write.
  • Global variables (if needed) or global functions need more descriptive names.
  • When using labels to jump, name them correctly to know what it does. For example avoid names like err1: and err2:, instead use something like out_free_device:
  • In general snake_case style is used, but it's not a rule.

Header guards

All C header files should be protected by header guards. Includes should be inside the guards.

#ifndef __HEADER_FILE_NAME_H__
#define __HEADER_FILE_NAME_H__

#include <otherheader.h>

...

#endif //__HEADER_FILE_NAME_H__

Static functions

If a function is private to a module (not exported through a header file), it should be declared static.

Hardcoded values

The code should not have "magic" values. Every constants should be in a separate constant variable, with the appropriate explanatory comment, if needed. If the constant values need to be used in other pieces of code, macros or enums should be used. Enums are preferred when defining several related constants.

#define BYTES_PER_PIXEL 4

int get_image_size (int num_of_pixels)
{
    /*return num_of_pixels * 4;  <-- Magic number alert! */
    return num_of_pixes * BYTES_PER_PIXELS;
}

Line Length

  • Limit line length to 80 characters

Braces

  • Put the brace in the same line as the if statement:

Yes:

if (2 == val) {
	/* Do something */
}

No:

if (2 == val) 
{
	/* Do something */
}
  • This applies to all non-function statement blocks (if, switch, for, while, do). E.g.:
switch (test) {
case 0:
	/* braces not required inside the case */
	return "disabled";
case 1:
	return "active";
default:
        return NULL;
}
  • For functions, put braces in a new line:
void some_function()
{
	/* Do something */
};
  • It's not required to use braces for single statement:

Yes:

if (2 == val) {
	/* Do something */
}

Yes too:

if (2 == val)
	/* Do something */
  • However is better to use them even in single lines to avoid inconsistencies like this:

No:

if (2 == val) {
	/* Do something */
	/* Do something else */
} else
	/* Do something */
  • Put braces after struct declaration line:
struct foo
{
	int x;
};

Spaces

Follow these Linux Kernel style rules to add spaces or not:

Yes:

  • After these keywords: if, switch, case, for, do, while.
  • Around most binary and ternary operators: = + - < > * /  % | & ^ <= >= ==  !=  ?  :

No:

  • After functions or sizeof, typeof, alignof, or __attribute__.
  • After unary operators: & * + - ~  ! .
  • Before the postfix increment & decrement unary operators: ++ --.
  • Around the . and -> structure member operators.
  • Do not leave trailing whitespace at the ends of lines.

Conditionals

  • Keep the constants at the left side of an equality comparison.
if ( NULL == var ) {
	/* Do something */
}

This is to avoid possible bugs like:

if ( var = NULL ) {
	/* Do something */
}

A derived good practice is to use const keyword as much as you can:

const int val = 1;

/*This should not compile*/
if (val = 2) {
	/* Do something */
}

Functions

Functions should be short and do only one thing. They shouldn’t have more than 5 or 10 local variables. If not, re-design it and split it into smaller functions.

Code Documentation

It's highly recommended to include documentation comments to functions, structs, unions, enums, etc.

  • Functions documentation should follow this kernel-doc comments format:
/**
 * function_name() - Brief description of function.
 * @arg1: Describe the first argument.
 * @arg2: Describe the second argument.
 *        One can provide multiple line descriptions
 *        for arguments.
 *
 * A longer description, with more discussion of the function function_name()
 * that might be useful to those using or modifying it. Begins with an
 * empty comment line, and may include additional embedded empty
 * comment lines.
 *
 * The longer description may have multiple paragraphs.
 *
 * Context: Describes whether the function can sleep, what locks it takes,
 *          releases, or expects to be held. It can extend over multiple
 *          lines.
 * Return: Describe the return value of function_name.
 *
 * The return value description can also have multiple paragraphs, and should
 * be placed at the end of the comment block.
 */
static <type> function_name(<type> arg1, <type> arg2)
{
	/* Do something */
}
  • Struct, union, and enum statements follows this kernel-doc comment format:
/**
 * struct struct_name - Brief description.
 * @member1: Description of member1.
 * @member2: Description of member2.
 *           One can provide multiple line descriptions
 *           for members.
 *
 * Description of the structure.
 */

For more information refer to Writing kernel-doc comments

Header Ordering

For header ordering we use an inside-out approach, this is, the local header goes first and the system headers go last so the header inclusion shoul go as follows:


1. Header file defining the functions implemented in the source file.

2. Other headers from the same project

3. Headers from non-standard projects

4. System headers (with angle brackets and .h extension)


A blank line should be added between each block of headers and the headers should go in alphabetical order in each block.

In an ideal world, header files should be self-contained and the include order shouldn't matter, however, this is not always the case, and if the order matters is a sign something is wrong in your code. Having the header file declaring the functions in the source file as the first include helps make sure my header is in fact self-contained. If it shows any error is a sign something is wrong.

Also, if an out-of-order include is needed it is a sign that something is not right in either your code or the external headers. If the problem is in your code, the best thing to do is to fix it but if not, the reason for the out-of-order include should be very well documented.

Here is an example of how the includes should look.

#include "my_module.h"

#include "other_header.h"

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


Previous: Coding Styles/C Index Next: Coding Styles/C++