Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
C

c-code-style

> 编程语言
Open source

Recommended C code style and coding rules for standard C99 or later

1.3K stars0 likes0 views
WebsiteGitHub

About

Recommended C code style and coding rules for standard C99 or later

Recommended C style and coding rules

This document describes C code style used by Tilen MAJERLE in his projects and libraries.

Table of Contents

  • The single most important rule
  • Recommended C style and coding rules
  • General rules
  • Comments
  • Functions
  • Variables
  • Structures, enumerations, typedefs
  • Compound statements
    • Switch statement
  • Macros and preprocessor directives
  • Documentation
  • Header/source files
  • Artistic Style configuration
  • Eclipse formatter

The single most important rule

Let's start with the quote from GNOME developer site.

The single most important rule when writing code is this: check the surrounding code and try to imitate it.

As a maintainer it is dismaying to receive a patch that is obviously in a different coding style to the surrounding code. This is disrespectful, like someone tromping into a spotlessly-clean house with muddy shoes.

So, whatever this document recommends, if there is already written code and you are patching it, keep its current style consistent even if it is not your favorite style.

General rules

Here are listed most obvious and important general rules. Please check them carefully before you continue with other chapters.

  • Use C99 standard
  • Do not use tabs, use spaces instead
  • Use 4 spaces per indent level
  • Use 1 space between keyword and opening bracket
c
/* OK */
if (condition)
while (condition)
for (init; condition; step)
do {} while (condition)

/* Wrong */
if(condition)
while(condition)
for(init;condition;step)
do {} while(condition)
  • Do not use space between function name and opening bracket
c
int32_t a = sum(4, 3);              /* OK */
int32_t a = sum (4, 3);             /* Wrong */
  • Never use __ or _ prefix for variables/functions/macros/types. This is reserved for C language itself
    • Prefer prv_ name prefix for strictly module-private functions
  • Use only lowercase characters for variables/functions/macros/types with optional underscore _ char
  • Opening curly bracket is always at the same line as keyword (for, while, do, switch, if, ...)
c
size_t i;
for (i = 0; i 
bool status = true;
  • Never compare against true, eg. if (check_func() == 1), use if (check_func()) { ... }
  • Always compare pointers against NULL value
c
void* ptr;

/* ... */

/* OK, compare against NULL */
if (ptr == NULL || ptr != NULL) {

}

/* Wrong */
if (ptr || !ptr) {

}
  • Always use pre-increment (and decrement respectively) instead of post-increment (and decrement respectively)
c
int32_t a = 0;
...

a++;            /* Wrong */
++a;            /* OK */

for (size_t j = 0; j 
void
my_func(size_t size) {
    int32_t* arr;
    arr = malloc(sizeof(*arr) * n); /* OK, Allocate memory */
    arr = malloc(sizeof *arr * n);  /* Wrong, brackets for sizeof operator are missing */
    if (arr == NULL) {
        /* FAIL, no memory */
    }

    free(arr);  /* Free memory after usage */
}

/* Wrong */
void
my_func(size_t size) {
    int32_t arr[size];  /* Wrong, do not use VLA */
}
  • Always compare variable against zero, except if it is treated as boolean type
  • Never compare boolean-treated variables against zero or one. Use NOT (!) instead
…
  • Always use /* comment */ for comments, even for single-line comment
  • Always include check for C++ with extern keyword in header file
  • Every function must include doxygen-enabled comment, even if function is static
  • Use English names/text for functions, variables, comments
  • Use lowercase characters for variables
  • Use underscore if variable contains multiple names, eg. force_redraw. Do not use forceRedraw
  • Never cast function returning void *, eg. uint8_t* ptr = (uint8_t *)func_returning_void_ptr(); as void * is safely promoted to any other pointer type
    • Use uint8_t* ptr = func_returning_void_ptr(); instead
  • Always use `` for C Standard Library include files, eg. #include
  • Always use "" for custom libraries, eg. #include "my_library.h"
  • When casting to pointer type, always align asterisk to type, eg. uint8_t* t = (uint8_t*)var_width_diff_type
  • Always respect code style already used in project or library

Comments

  • Comments starting with // are not allowed. Always use /* comment */, even for single-line comment
c
//This is comment (wrong)
/* This is comment (ok) */
  • For multi-line comments use space+asterisk for every line
c
/*
 * This is multi-line comments,
 * written in 2 lines (ok)
 */

/**
 * Wrong, use double-asterisk only for doxygen documentation
 */

/*
* Single line comment without space before asterisk (wrong)
*/

/*
 * Single line comment in multi-line configuration (wrong)
 */

/* Single line comment (ok) */
  • Use 12 indents (12 * 4 spaces) offset when commenting. If statement is larger than 12 indents, make comment 4-spaces aligned (examples below) to next available indent
c
void
my_func(void) {
    char a, b;

    a = call_func_returning_char_a(a);          /* This is comment with 12*4 spaces indent from beginning of line */
    b = call_func_returning_char_a_but_func_name_is_very_long(a);   /* This is comment, aligned to 4-spaces indent */
}

Functions

  • Every function which may have access from outside its module, must include function prototype (or declaration)
  • Function name must be lowercase, optionally separated with underscore _ character
c
/* OK */
void my_func(void);
void myfunc(void);

/* Wrong */
void MYFunc(void);
void myFunc();
  • When function returns pointer, align asterisk to return type
c
/* OK */
const char* my_func(void);
my_struct_t* my_func(int32_t a, int32_t b);

/* Wrong */
const char *my_func(void);
my_struct_t * my_func(void);
  • Align all function prototypes (with the same/similar functionality) for better readability
c
/* OK, function names aligned */
void        set(int32_t a);
my_type_t   get(void);
my_ptr_t*   get_ptr(void);

/* Wrong */
void set(int32_t a);
const char * get(void);
  • Function implementation must include return type and optional other keywords in separate line
c
/* OK */
int32_t
foo(void) {
    return 0;
}

/* OK */
static const char*
get_string(void) {
    return "Hello world!\r\n";
}

/* Wrong */
int32_t foo(void) {
    return 0;
}

Variables

  • Make variable name all lowercase with optional underscore _ character
c
/* OK */
int32_t a;
int32_t my_var;
int32_t myvar;

/* Wrong */
int32_t A;
int32_t myVar;
int32_t MYVar;
  • Group local variables together by type
c
void
foo(void) {
    int32_t a, b;   /* OK */
    char a;
    char b;         /* Wrong, char type already exists */
}
  • Do not declare variable after first executable statement
c
void
foo(void) {
    int32_t a;
    a = bar();
    int32_t b;      /* Wrong, there is already executable statement */
}
  • You may declare new variables inside next indent level
c
int32_t a, b;
a = foo();
if (a) {
    int32_t c, d;   /* OK, c and d are in if-statement scope */
    c = foo();
    int32_t e;      /* Wrong, there was already executable statement inside block */
}
  • Declare pointer variables with asterisk aligned to type
c
/* OK */
char* a;

/* Wrong */
char *a;
char * a;
  • When declaring multiple pointer variables, you may declare them with asterisk aligned to variable name
c
/* OK */
char *p, *n;

Structures, enumerations, typedefs

  • Structure or enumeration name must be lowercase with optional underscore _ character between words
  • Structure or enumeration may contain typedef keyword
  • All structure members must be lowercase
  • All enumeration members must be uppercase
  • Structure/enumeration must follow doxygen documentation syntax

When structure is declared, it may use one of 3 different options:

  1. When structure is declared with name only, it must not contain _t suffix after its name.
c
struct struct_name {
    char* a;
    char b;
};
  1. When structure is declared with typedef only, it has to contain _t suffix after its name.
c
typedef struct {
    char* a;
    char b;
} struct_name_t;
  1. When structure is declared with name and typedef, it must not contain _t for basic name and it has to contain _t suffix after its name for typedef part.
c
typedef struct struct_name {
    char* a;
    char b;
    char c;
} struct_name_t;

Examples of bad declarations and their suggested corrections

c
/* a and b must be separated to 2 lines */
/* Name of structure with typedef must include _t suffix */
typedef struct {
    int32_t a, b;
} a;

/* Corrected version */
typedef struct {
    int32_t a;
    int32_t b;
} a_t;

/* Wrong name, it must not include _t suffix */
struct name_t {
    int32_t a;
    int32_t b;
};

/* Wrong parameters, must be all uppercase */
typedef enum {
    MY_ENUM_TESTA,
    my_enum_testb,
} my_enum_t;
  • When initializing structure on declaration, use C99 initialization style
c
/* OK */
a_t a = {
    .a = 4,
    .b = 5,
};

/* Wrong */
a_t a = {1, 2};
  • When new typedef is introduced for function handles, use _fn suffix
c
/* Function accepts 2 parameters and returns uint8_t */
/* Name of typedef has `_fn` suffix */
typedef uint8_t (*my_func_typedef_fn)(uint8_t p1, const char* p2);

Compound statements

  • Every compound statement must include opening and closing curly bracket, even if it includes only 1 nested statement
  • Every compound statement must include single indent; when nesting statements, include 1 indent size for each nest
c
/* OK */
if (c) {
    do_a();
} else {
    do_b();
}

/* Wrong */
if (c)
    do_a();
else
    do_b();

/* Wrong */
if (c) do_a();
else do_b();
  • In case of if or if-else-if statement, else must be in the same line as closing bracket of first statement
c
/* OK */
if (a) {

} else if (b) {

} else {

}

/* Wrong */
if (a) {

}
else {

}

/* Wrong */
if (a) {

}
else
{

}
  • In case of do-while statement, while part must be in the same line as closing bracket of do part
c
/* OK */
do {
    int32_t a;
    a = do_a();
    do_b(a);
} while (check());

/* Wrong */
do
{
/* ... */
} while (check());

/* Wrong */
do {
/* ... */
}
while (check());
  • Indentation is required for every opening bracket
c
if (a) {
    do_a();
} else {
    do_b();
    if (c) {
        do_c();
    }
}
  • Never do compound statement without curly bracket, even in case of single statement. Examples below show bad practices
c
if (a) do_b();
else do_c();

if (a) do_a(); else do_b();
  • Empty while, do-while or for loops must include brackets
c
/* OK */
while (is_register_bit_set()) {}

/* Wrong */
while (is_register_bit_set());
while (is_register_bit_set()) { }
while (is_register_bit_set()) {
}
  • If while (or for, do-while, etc) is empty (it can be the case in embedded programming), use empty single-line brackets
…
  • Avoid using #ifdef or #ifndef. Use defined() or !defined() instead
c
#ifdef XYZ
/* do something */
#endif /* XYZ */
  • Always document if/elif/else/endif statements
c
/* OK */
#if defined(XYZ)
/* Do if XYZ defined */
#else /* defined(XYZ) */
/* Do if XYZ not defined */
#endif /* !defined(XYZ) */

/* Wrong */
#if defined(XYZ)
/* Do if XYZ defined */
#else
/* Do if XYZ not defined */
#endif
  • Do not indent sub statements inside #if statement
c
/* OK */
#if defined(XYZ)
#if defined(ABC)
/* do when ABC defined */
#endif /* define

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Ccc-code-stylec-rulescoding

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言