RidgeRun Developer Manual - Coding Styles - C
WORK IN PROGRESS. Please Contact RidgeRun OR email to support@ridgerun.com if you have any questions. |
RidgeRun Developer Manual |
---|
Coding Styles |
Development Tools |
Editors |
Debugging Tools |
|
Profiling Tools |
Methodologies |
Design Patterns |
RidgeRun Developer Manual/Testing |
RidgeRun Developer Manual/Build Systems |
Contact Us |
Introduction to 'C' Coding Styles
RidgeRun is an embedded software company with wide of experience in software development based on C. When writing software source code there are many coding styles as the concept covers a lot of aspects (some of them subjective). In genera, when working on C applications (such as GStreamer plugins, for example) we follow the GStreamer standard.
Good practices
Here are some good practices that are applied to C code.
Be consistent with current code
In general, if you are adding code to an existent code, be consistent with the coding standard already being used. If no standard is used then follow this guide.
Comments
- Always use /*ANSI-C style comments*/
- Avoid inline comments:
Yes:
/*This is a comment*/ if ( NULL == var ) { /*...*/ }
No:
if ( NULL == var ) { /*This is a comment*/ /*...*/ }
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> * * The contents of this software are proprietary and confidential to RidgeRun, * LLC. No part of this program may be photocopied, reproduced or translated * into another programming language without prior written consent of * RidgeRun, LLC. The user is free to modify the source code after obtaining * a software license from RidgeRun. All source code changes must be provided * back to RidgeRun without any encumbrance. */
Consistent indentation
- Use only spaces and indent 2 paces at a time. Don't use tabs.
Avoid unnecessary separators
One single empty line is fine to separate logical blocks. Avoid multiple empty lines, commented empty lines, etc.
Variable naming standard
All variables names should follow the same standard. If the code is an extension of an existing framework/library, it should follow the existing standard. For example:
int mixedCamelCaseVariable; int CamelCaseVariable; int snake_case_variable; int horribleStandard_Variable;
For Gstreamer we use snake_case.
Method/function naming standard
All method names should follow the same standard. If the code is an extension of an existing framework/library, it should follow the existing standard. For example:
void mixedCamelCaseFunction (); void CamelCaseFunction (); void snake_case_function (); void horribleStandard_Function ();
For Gstreamer we use snake_case.
Class/struct naming standard
All class/struct names should follow the same standard. If the code is an extension of an existing framework/library, it should follow the existing standard. Additionally, if typedef aliasing is used, it should always be in the same line or always in a separate line.
typedef struct _mixedCamelCaseStruct mixedCamelCaseStruct; typedef struct _CamelCaseStruct CamelCaseStruct; typedef struct _underscore_separated_struct underscore_separated_struct; typedef struct _horribleStandard_Sturct horribleStandard_Struct;
Descriptive names
All variables and function names should have descriptive names. They should be descriptive enough to almost know what the function/variable is for, without understanding the code. For example:
/*Bad function name*/ void callback () { } /*Better function name*/ void new_data_received_callback () { } /*Bad variable name*/ int n=0; /*Better variable name*/ int num_buffers;
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 is to be used in other pieces of code, a global constant or macro should be used.
#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) { ... }
No:
if (2 == val) { ... }
- Put braces in a new line for functions:
void some_function() { /*Do something*/ };
- Use braces for all statements (even for one line statements):
Yes:
if (2 == val) { do_something(); }
No:
if (2 == val) do_something();
- Put braces below a case statement, with no indentation:
switch (i) { case 0: { ++i; } }
- Put braces after struct declaration line:
struct foo { int x; };
Conditionals
- Keep the constants at the left side of an equality comparison.
if ( NULL == var ) { /*...*/ }
This is to avoid possible bugs like:
if ( var = NULL ) { /*...*/ }
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) { /*...*/ }
Switch
- Put case labels indented 2 spaces to the right of the switch statement:
switch (i) { case 0: { ++i; } }
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>