Skip to content

Instantly share code, notes, and snippets.

@Oxore
Last active October 13, 2018 15:33
Show Gist options
  • Save Oxore/b06984403855ceefefbadfc22d4984cd to your computer and use it in GitHub Desktop.
Save Oxore/b06984403855ceefefbadfc22d4984cd to your computer and use it in GitHub Desktop.
My own C code style
---
BasedOnStyle: LLVM
# Strict
AllowShortIfStatementsOnASingleLine: false
BreakBeforeBinaryOperators: All
BreakBeforeBraces: Linux
BreakBeforeTernaryOperators: true
IndentCaseLabels: false
MaxEmptyLinesToKeep: 2
IndentWidth: 4
PointerAlignment: Right
UseTab: Never
# Non strict or not working properly
AlignAfterOpenBracket: Align
AlignConsecutiveDeclarations: true
AlignEscapedNewlines: DontAlign
AlignTrailingComments: false
SortIncludes: false
SpaceAfterCStyleCast: false

Code style

Summary of the most strict rules

  • Max line width is 80 columns.
  • Indentation width is 4 spaces.
  • Never use tabs.
  • Consecutive declarations must be aligned
  • Curly braces for functions and for, while, if, else, switch statements are the same as in the Linux code style.
  • No space between function name and it's arguments list in parentheses.
  • Exactly one space between for, while, if, switch statement and it's expression in parentheses.
  • Every case is on the same level as it's switch statement.
  • for, while, if, else, switch statements has no curly braces on the corresponding code block if block contains only one operator (see Curly braces).
  • Function declaration and prototype declared in one line. Type, name and arguments list are on the same line.
  • Too long function arguments list carried over and indented one level relatively to function name. The same is for function declaration, prototype and invocation.
  • Line breaking operator (e.g. +, =, %, ?) must be carried over with new line. (clang-format BreakBeforeBinaryOperators: All, BreakBeforeTernaryOperators: true)
  • No more than two empty lines anywhere.
  • Pointer declaration and dereferencing asterisk (*) as long as addressing ampersand (&) are adjacent to the data or function name, not to type name.
  • No #ifndef __HEADER_H__ include guards and no includes in headers.
  • No executable code in headers. Let defines, types, typedefs and functions prototypes only.
  • Naming is lowercase with underscores_between_words and UPPERCASE_FOR_DEFINES.
  • Minimum of typedefs.
  • Minimum of comments (except for documenting software like doxygen).

Naming convention

Classic C programming approach is procedural programming and the best naming style for this is the following.

  • Minimum of typedefs, better not to use typedefs at all.
  • spaces_between_words in function and variable names.
  • All names are lowercase, if other is not necessary.
  • Preprocessor definitions are UPPERCASE_ONLY.
  • External preprocessor definitions _STARTS_WITH_UNDERSCORE and defined on compiler invocation as -D_DEFINITION_NAME.

Completely bad:

#define errcode 15;

#define myType int;

int variableName;
int another_Variable_Name;

TypedefedStruct TypedefedVariableName;

void *functionName(myType arg_1_name, char *arg_2);
void  AnotherFunctionName(int arg_1, void arg_2);

Sort of (formal) good:

#define ERR_CODE_NO_ERROR 0;

int   variable_name;
char *word;
float disp;

struct some_struct struct_variable;

void *function_name(size_t arg_name1, char *arg2);

Sometimes it is better to shorten some names a little, especially if it has very small scope and pattern designation like i or j iterator in a loop. Shorten names are not actually bad. Linux code style has better explanation for naming.

Curly braces

Braces example

Good:

int *function(int arg1, int *arg2)
{
    int *a = malloc(arg1, sizeof(int))
    while (arg1-- > 0) {
        if (arg2[arg1] & MASK) {
            a[arg1] = arg2[arg1];
            a[arg1] += arg1 >= 0 ? arg2[arg1-] : 0;
        } else if (arg2[arg1] & ANOTHER_MASK) {
            free(a);
            set_my_errno(ERR_CODE);
            return 0;
        }
    }
}
if (expression)
    function();
else
    other_function();

if (expression)
    function();
else {
    other_function();
    some_other_function();
}

if (expression) {
    function();
    other_function();
} else
    some_other_function();

if (expression)
    operator();
/* Single line loop is ok when no operators in body */
while ((list = list->next));

Bad:

if (expression) {
    function();
} else {
    other_function();
    some_other_function();
}

if (expression) {
    function();
    other_function();
} else {
    some_other_function();
}

/* Seems like you are trying to hide something */
if (expression) operator();

/* Ugly */
while ((list = list->next))
    ;

Struct declaration

struct mystruct {
    int  field1;
    int *field2;
}

Struct and array initialization is not too strict. You can do either

struct mystruct aaa = {
    .field1 = 0,
    .field2 = 0,
};

or

struct mystruct aaa = {.field1 = 0, .field2 = 0};

as you wish, depending on how long the initialization list is and how readable it could be. But following examples looks ugly. Please don't write code in such way:

struct mystruct aaa = {.field1 = 0,
                       .field2 = 0};
struct mystruct bbb =
{
    .field1 = 0,
    .field2 = 0,
};
struct mystruct aaa = { .field1 = 0, .field2 = 0 };

Function declaration

Do not omit argument names in function prototypes. They may serve you as a quick reference, especially since no documentation system is used. Use the same argument names as in function declaration itself.

Bad:

int function(int, float, char *);

Good:

int function(int arg1, float arg2, char *arg3);

Carrying over

If you have a function prototype or a function declaration more than 80 characters long... do your best to avoid this! But if there is an essential reason to have such an ugly function, then just break arguments list and align next lint to the function name with one extra level of indent.

int function_with_intentionally_long_name(struct with_long_name argument1,
        float arg2, char *not_too_long_name);
//  |---^ - Indentation

void *shorter_name(struct with_long_name hehe, int fits, char * const and_this,
          char *but_this_not, char *and_this_is_going_to_be_here,
          struct okay lets_go_crazy_with_this, int awww);
//    |---^ - Indentation

char * const char *function(struct mystruct arg1, int arg2, char *arg3, int arg4,
                       float arg5);
//                 |---^ - Indentation

The same is for executable lines;

int sum_of_variables = data_struct->array[i][j] + meaningful_variable
                           + length < size ? length : 0;
//                     |---^ - Indentation (new line with linebreaking operator)

int i_tried_of_this_stupid_longnaming
        = max(0, data_struct->array[i][j]->holy_shit_how_long_this_is);
//  |---^ - Indentation (new line with linebreaking operator)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment