Epitech c Coding Style-1
Epitech c Coding Style-1
C Coding Style
Keep your code nice and clean
6
The Epitech C Coding Style is a set of rules that have been created within the school, and that you have to
follow.
It covers:
It is compulsory on all programs written in C as part of Epitech’s projects, regardless of the year or unit, as
long as a langage to program in is imposed.
It applies to all source (.c) and header files (.h) present in the repository, as well as Makefiles.
Adopting a coding style makes reading code written by others easier. As such, it facilitates group work, as
well as help given to you by the educational team and the assistants.
It is also an excellent way to encourage structuring the code and making it clearer, and thus facilitates:
• its reading;
• its debugging;
• its maintenance;
• its internal logic definition;
• its reusability;
• writing tests;
• adding new features;
• and even more. . .
A clean and structured code always feels nice to look at, so give yourself this treat. ;)
When you are facing a choice and you do not know what decision to make, always ask
yourself which one helps you make your code clearer, ergonomic and flexible.
In case of uncertainty or ambiguity regarding the principles and rules specified in this document, please
refer to your local educational manager.
1
Rules are categorized into 4 severity levels: fatal , major , minor and info .
Fatal rules are related to the objective itself of programming in C. Violating even once a fatal rule will
make your project rejected and not evaluated at all.
Major rules are related to the structure of the code and to practices that are detrimental to the production
of a code of good quality. Violating any of the major rules (even once) is a major problem and must be
corrected as a priority concern.
Minor rules are generally related to the visual presentation of the code, which can make the code dif-
ficult to read if not followed consistently. Repeatedly violating minor rules must be avoided, as it creates
inconsistently formatted code, which in turn makes it harder to read.
Info rules are related to specific trivial points that are not as important as other rules. Each of these rules
are however anchored in good practices, and should as such be followed to ensure a code of the best quality
possible.
There are many and many ways to produce unclean code, and as such many rules to follow in order to avoid
them.
Even though one cannot mention all of them in this document, they still have to be respected.
We call them implicit rules when not explicitly defined in this document.
The Coding Style is a purely syntactic convention, so it can not be used as an excuse if
your program does not work. ;)
Although following the coding style is not required in all projects, this is not a reason for
not always sequencing and structuring your code.
Most of the rules in this coding style can be applied to all languages, so they can be
useful when you are doing projects in different languages.
It is easier and quicker to follow the coding style from the beginning of a project rather
than to adapt existing code at the end.
This document is inspired by the Linux Kernel Coding Style, and is freely adapted from
Robert C. Martin’s excellent book Clean Code.
2
BANANA
The adherence to the coding style is partially checked during evaluations by a tool called the Bot Analyzing
Nomenclature And Nonsensical Arrangements, better known as Banana.
You can (and should) also use this tool to check that your code follows a good portion of the rules.
Other rules are checked manually, with the great tool that are your eyes.
The rules are tagged with three possible levels of support by Banana:
USING BANANA
The script will make sure that you always have the latest version of Banana.
If you find any problem or have any question regarding Banana, you can open an issue there, and a Banana
developer will happily answer you.
3
C-O - FILES ORGANIZATION
C-O1 - CONTENTS OF THE REPOSITORY
The repository must not contain compiled (.o, .a, .so, . . . ), temporary or unnecessary files (*~, #*#, etc.).
Git has a wonderful way to help you keep your repository clean. ;)
A source file must match a logical entity, and group all the functions associated with that entity.
Grouping functions that are not related to each other in the same file has to be avoided.
You are allowed to have 10 functions (including at most 5 non-static functions) in total per file.
Beyond these amounts, you must subdivide your logical entity into several sub-entities.
The name of the file must define the logical entity it represents, and thus be clear, precise, explicit and
unambiguous.
For example, files like string.c or algo.c are probably incorrectly named.
Names like string_toolbox.c or pathfinding.c would be more appropriate.
All file names and folders must be in English, according to the snake_case convention (that is, only com-
posed of lowercase, numbers, and underscores).
Abbreviations are tolerated as a way to significantly reduce the size of a name only if it
does not lose its meaning.
4
C-G - GLOBAL SCOPE
MULTILINE STATEMENTS
Do not use the backslash character (\) to break lines in C files, because it will only visually
break the line.
As such, you will get into trouble regarding the coding style’s rules!
5
C-G1 - FILE HEADER
C files (.c, .h, . . . ) and every Makefiles must always start with the standard header of the school.
This header is created in Emacs using the Ctrl + c Ctrl + h command.
For C files:
/*
** EPITECH PROJECT , $YEAR
** $ N A M E _ O F _ THE_PROJECT
** File description :
** No file there , just an epitech header example .
** You can even have multiple lines if you want !
*/
For Makefiles:
##
## EPITECH PROJECT , $YEAR
## $ N A M E _ O F _ THE_PROJECT
## File description :
## No file there , just an epitech header example .
## You can even have multiple lines if you want !
##
Always add a meaningful description of the file, you have a unlimited amount of line to
do so.
Inside a source file, implementations of functions must be separated by one and only one empty line.
6
C-G3 - INDENTATION OF PREPROCESSOR DIRECTIVES
Indentation must be done in the same way as in the C-L2 rule (groups of 4 spaces, no
tabulations).
However, preprocessor directives must be indented independently of all the other
code.
# ifndef WIN32
# include < stdbool .h >
# if defined ( __i386__ ) || defined ( __x86_64__ )
const size_t PAGE_SIZE = 4096;
# else
# error " Unknown architecture "
# endif
struct coords {
int x ;
int y ;
};
# endif
A constant is considered as such if and only if it is correctly marked with the const key-
word. Watch out, this keyword follows some particular and sometimes surprising rules!
C-G5 - include
7
C-G6 - LINE ENDINGS
git config can help you keep your lines correctly ended.
This greatly helps you when you want to modify an important value in your program, because you do not
need to find all occurences of this value scattered throughout your code, and only need to change it in one
place.
8
C-F - FUNCTIONS
C-F1 - COHERENCE OF FUNCTIONS
A function should only do one thing, not mix different levels of abstraction, and respect the single-responsibility
principle (a function should be changed only for one reason).
For example, a call to malloc(), a call to allocate_user(), and a call to create_user() all
have 3 different levels of abstraction.
The name of a function must define the task it executes and must contain a verb.
For example, the vowels_nb() and dijkstra() functions are incorrectly named.
get_vowels_number() and search_shortest_path() are more meaningful and precise.
All function names must be in English, according to the snake_case convention (meaning that it is composed
only of lowercase, numbers, and underscores).
Abbreviations are tolerated if they significantly reduce the name without losing mean-
ing.
The length of a line must not exceed 80 columns (not to be confused with 80 characters).
The line break character (\n) is part of the line, and thus counts in its length.
Even though this rule especially applies to functions, it applies to all C files, as well as
Makefiles.
9
C-F4 - NUMBER OF LINES
The body of a function should be as short as possible, and must not exceed 20 lines.
int main ( void ) /* this function is 2 - line - long */
{
printf ( " hello , world \ n " ) ;
return 0;
}
The maximum length of a function is inversely proportional to the complexity and indentation level of
that function. case-statement, where you have lots of small things for a lot of different cases, it’s OK to
have a longer function.
A function taking no parameters must take void as a parameter in the function declaration.
phys_addr_t alloc_frame () ; /* C - F6 violation */
phys_addr_t alloc_frame ( void ) ; /* OK */
The two syntaxes above have different meanings, and have different interesting be-
haviours.
10
C-F8 - COMMENTS INSIDE A FUNCTION
Nested functions are not allowed, because they are an extension of the GNU C standard, and because they
greatly increase complexity.
11
C-L - LAYOUT INSIDE A FUNCTION SCOPE
C-L1 - CODE LINE CONTENT
The only exception to this rule is the for loop control structure, for which one statement is allowed in each
of the three parts (initialization, loop condition, and post-iteration operation).
a = b = c = 0; /* C - L1 violation */
a ++; b ++; /* C - L1 violation */
if (( ptr = malloc ( sizeof ( struct my_struct ) ) ) != NULL ) /* C - L1 violation */
if ( cond ) return ( ptr ) ; /* C - L1 violation */
for ( int i = 0; i < 42; i ++) { /* OK */
...
}
for ( int i = j = 0; i < 42; i ++) { /* C - L1 violation */
...
}
for ( int i = 0; i < 42; i ++ , j - -) { /* C - L1 violation */
...
}
C-L2 - INDENTATION
When entering a new scope (e.g.: control structure), the indentation level must be incremented.
// OK
int main ( void )
{
char letter = 'H ';
int number = 14;
12
// Incorrect
int main ( void )
{
int i ;
}
// Incorrect
int main ( void )
{
if ( true ) {
return (0) ;
}
}
13
C-L3 - SPACES
When using a space as a separator, one and only one space character must be used.
However, there must be no spaces between the name of a function and the opening parenthesis, after a
unary operator, before a semicolon, or before a comma.
In the precise case of a for control structure, if a semicolon inside the parentheses is not immediately fol-
lowed by another semicolon, it must be followed by a space.
All binary and ternary operators must be separated from their arguments by a space on both sides.
return 1; /* OK */
return (1) ; /* OK */
return (1) ; /* C - L3 violation */
return (1 + 2) ; /* C - L3 violation */
break ; /* OK */
break ; /* C - L3 violation */
add_numbers (1 , 2) ; /* OK */
add_numbers (1 , 2) ; /* C - L3 violation */
sum = term1 + 2 * term2 ; /* OK */
s = sizeof ( struct file ) ; /* OK */
s = sizeof ( struct file ) ; /* C - L3 violation */
for ( size_t i ; str [ i ] != ' \0 '; i ++) { /* OK */
...
}
for ( size_t i ; str [ i ] != ' \0 ' ; i ++) { /* C - L3 violation ( twice ) */
...
}
14
C-L4 - CURLY BRACKETS
Opening curly brackets must be at the end of the line, after the content it precedes, except for functions
definitions where they must be placed alone on their line.
Closing curly brackets must be alone on their line, except in the case of else/else if/do while control struc-
tures, enum declarations, or structure declarations (with or without an associated typedef).
In the case of a single-line scope, omitting curly brackets is tolerated, but you should
think about all the modifications you will have to make if you want to add a new state-
ment to the block. This can also introduce some nasty bugs!
Even though this primarily applies to the contents of functions, this rule also applies to
code outside functions, including header files’.
15
C-L5 - VARIABLE DECLARATIONS
The for control structures may also optionally declare a variable in their initialization part.
Nothing prevents you from declaring and assigning a variable on the same line.
biggest = MAX (a , b ) ;
smallest = MIN (a , b ) ;
long rest ; /* C - L5 violation */
while ( smallest > 0) {
rest = biggest % smallest ;
biggest = smallest ;
smallest = rest ;
}
return a ;
}
16
C-L6 - BLANK LINES
A blank line must separate the variable declarations from the remainder of the function.
No other blank lines must be present in the function.
int sys_open ( char const * path )
{
int fd = thread_reserve_fd () ;
struct filehandler * fhandler = NULL ;
/* OK */
if ( fd < 0) {
return -1;
}
if ( fs_open ( path , & fhandler ) ) {
thread_free_fd ( fd ) ;
return -1;
}
/* C - L6 violation */
t h r e a d _ s et_ fd_ha ndle r ( fd , fhandler ) ;
return fd ;
}
17
C-V - VARIABLES AND TYPES
C-V1 - NAMING IDENTIFIERS
All identifier names must be in English, according to the snake_case convention (meaning it is composed
exclusively of lowercase, numbers, and underscores).
The type names defined with typedef must end with _t.
The names of macros and global constants and the content of enums must be written in UPPER_SNAKE_CASE.
# define IS_PAGE_ALIGNED ( x ) (!(( x ) & ( PAGE_SIZE - 1) ) ) /* OK */
enum arch { /* OK */
I386 = 0 ,
X86_64 ,
ARM ,
ARM64 ,
SPARC ,
POWERPC ,
};
const float PI = 3.14159; /* OK */
typedef int age ; /* C - V1 violation */
typedef struct int_couple pixel_t ; /* OK */
Abbreviations are tolerated as long as they significantly reduce the name length without
losing meaning.
C-V2 - STRUCTURES
Variables can be grouped together into a structure if and only if they form a coherent entity.
Structures must be kept as small as possible.
struct person { /* OK */
char * name ;
unsigned int age ;
float salary ;
};
18
C-V3 - POINTERS
The asterisk (*) must be attached to the associated variable, with no spaces in between.
It must also be preceded by a space, except when it is itself preceded by another asterisk.
This includes using the asterisk to declare or dereference a pointer.
When used in a cast, the asterisk must have a space on its left side, but not on its right side.
int * a ; /* OK */
int * a ; /* C - V3 violation */
int * a ; /* C - V3 violation */
char ** argv ; /* OK */
char ** argv ; /* C - V3 violation */
char * * argv ; /* C - V3 violation */
char ** argv ; /* C - V3 violation */
int a = 3 * b ; /* OK */
int strlen ( char const * str ) ; /* OK */
int strlen ( char const * str ) ; /* OK */
char * my_strdup ( char const * str ) ; /* OK */
char * my_strdup ( char const * str ) ; /* C - V3 violation */
my_put_nbr (* ptr ) ; /* OK */
my_put_nbr (* ptr ) ; /* C - V3 violation */
( int *) ptr ; /* OK */
( int *) ptr ; /* C - V3 violation */
( int * ) ptr ; /* C - V3 violation */
void (* func_ptr ) ( int ) = & func ; /* OK */
(* func_ptr ) (42) ; /* OK */
19
C-C - CONTROL STRUCTURES
Unless otherwise specified, all control structures are allowed.
A conditionnal block (while, for, if, else, . . . ) must not contain more than 3 branches.
Arrays of function pointers and switch instructions are very useful when you want to
have numerous different behaviours that can result from the check of an element.
Take care to choose the most suitable one.
If you need multiple levels of branches, you probably need to refactor your function into
sub-functions.
if (...) { /* OK */
do_something () ;
} else if (...) {
do_s omething_else () ;
} else {
do_s omething_more () ;
}
if (...) {
do_something () ;
} else if (...) {
do_s omething_else () ;
} else if (...) {
do_s omething_more () ;
} else { /* C - C1 violation */
do_o ne_last_thing () ;
}
while (...) { /* OK */
if (...) {
do_something () ;
}
}
20
else if branching does not add one, but two levels of depth, as it is considered to be an
if inside an else.
21
C-C2 - TERNARY OPERATORS
The use of ternary operators is allowed as far as it is kept simple and readable, and if it does not obfuscate
code.
C-C3 - goto
Using the goto keyword is forbidden, because it can very quickly participate in the creation of infamous
spaghetti code, which is completely illegible.
22
C-H - HEADER FILES
C-H1 - CONTENT
• function prototypes,
• type declarations,
• structure declarations,
• enumeration declarations,
• global variable/constant declarations,
• macros,
• static inline functions.
All these elements must only be found in header files, and thus not in source files.
Including a header from another header is allowed as long as the header file itself needs
it.
If a source file requires it, but not the header file itself, it should then be included in the
source file instead.
C-H3 - MACROS
Macros must match only one statement, and fit on a single line.
# define PI 3. 14 15 92 653 58 97 932 38 46 /* OK */
# define DELTA (a , b , c ) (( b ) * ( b ) - 4 * ( a ) * ( c ) ) /* OK */
# define PRINT_NEXT ( num ) { num ++; printf ( " % d " , num ) ;} /* C - H3 violation */
# define ERROR_MESSAGE " Multiline macros " \
" have to be avoided " /* C - H3 violation */
Using a macro to shorten a long expression is rarely a valid reason to use a macro:
// Unnecessary and obfuscates the code
# define WIN ( data - > object - > scene - > state - > window )
23
C-A - ADVANCED
C-A1 - CONSTANT POINTERS
When creating a pointer, if the pointed data is not (or should not be) modified by the function, it should be
marked as constant (const).
C-A2 - TYPING
Prefer the most accurate types possible according to the use of the data.
int counter ; /* C - A2 violation */
unsigned int counter ; /* OK */
unsigned int get_obj_size ( void const * object ) /* C - A2 violation */
size_t get_obj_size ( void const * object ) /* OK */
∇ Terminal - + x
∼/Epitech Documentation> cat -e correct.c
int main(void) {$
return 0;$
}$
∼/Epitech Documentation> cat -e incorrect.c
int main(void) {$
return 0;$
}
A sequence of zero or more non- <newline> characters plus a terminating <newline> character.
24
C-A4 - static
Global variables and functions that are not used outside the compilation unit to which they belong should
be marked with the static keyword.
Be careful not to confuse the different uses of the static keyword. It does very different
things depending on where you use it.
25