Этот документ описывает стиль C -кода, используемый Тилен Маджерле в его проектах и библиотеках.
Давайте начнем с цитаты с сайта разработчика Gnome.
Единственное наиболее важное правило при написании кода: проверьте окружающий код и попробуйте подражать его .
Как сопровождающий, тревожить, чтобы получить патч, который, очевидно, находится в другом стиле кодирования для окружающего кода. Это неуважительно, как кто-то, кто попадает в безупречно чистую дом с грязными туфлями.
Итак, что бы ни рекомендовал этот документ, если уже есть написанный код, и вы его исправляете, сохраняйте его текущий стиль последовательным, даже если это не ваш любимый стиль.
VSCODE поставляется с предварительно установленным инструментом clang-format
(часть пакета LLVM), который был разработан, чтобы помочь разработчикам с инструментом автоматического формата во время разработки кода.
Таким образом, он позволяет пользователям форматировать код в изменении файла (и сохранение). Когда файл будет сохранен, VSCODE попытается вызвать формат Clang и отформатировать код. Правила для использования находятся в файле .clang-format
. Если Clang-Format не может найти правила в пути текущего файла, он будет перейти до корня, пока не найден. Если все еще нет, правила по умолчанию используются, а затем используются.
Этот репозиторий содержит всегда актуальный файл .clang-format
с соответствующими правилами. Вы можете разместить папку в корне или в вашем проекте или даже в корне проектов по разработке программного обеспечения -> Используйте один файл для всех!
Некоторые конфигурации должны быть включены:
Ключевые слова не должны , не должны , не должны, не должны , не должны , рекомендуется , не рекомендуется , может и необязательно в этом документе должно быть интерпретировано, как описано в BCP 14 [RFC2119] [RFC8174]
Здесь перечислены наиболее очевидные и важные общие правила. Пожалуйста, проверьте их внимательно, прежде чем продолжить другие главы.
clang-format
должен использоваться с форматированным файлом, прикрепленным к этому репозиторию (версия 15.x
-минимум)C11
4
места на уровень отступа1
пространство между ключевым словом и открытием. /* OK */
if ( condition )
while ( condition )
for ( init ; condition ; step )
do {} while ( condition )
/* Wrong */
if ( condition )
while ( condition )
for ( init ; condition ; step )
do {} while ( condition )
int32_t a = sum ( 4 , 3 ); /* OK */
int32_t a = sum ( 4 , 3 ); /* Wrong */
__
или _
префикс для переменных/функций/макросов/типов. Это зарезервировано для самого языка Cprv_
для строгого модуля-частного (статического) функцийlibname_int_
или libnamei_
_
charfor
, while
, do
, switch
, if
, ...) size_t i ;
for ( i = 0 ; i < 5 ; ++ i ) { /* OK */
}
for ( i = 0 ; i < 5 ; ++ i ){ /* Wrong */
}
for ( i = 0 ; i < 5 ; ++ i ) /* Wrong */
{
}
int32_t a ;
a = 3 + 4 ; /* OK */
for ( a = 0 ; a < 5 ; ++ a ) /* OK */
a = 3 + 4 ; /* Wrong */
a = 3 + 4 ; /* Wrong */
for ( a = 0 ; a < 5 ; ++ a ) /* Wrong */
func_name ( 5 , 4 ); /* OK */
func_name ( 4 , 3 ); /* Wrong */
global
переменные до какого -либо значения по умолчанию (или NULL
), реализуйте его в специальной функции init
(если это необходимо). static int32_t a ; /* Wrong */
static int32_t b = 4 ; /* Wrong */
static int32_t a = 0 ; /* Wrong */
В встроенных системах очень распространено, что воспоминания ОЗУ разбросаны по разным местам памяти в системе. Быстро становится сложно обрабатывать все случаи, особенно когда пользователь объявляет пользовательские разделы ОЗУ. Скрипт запуска ответственен за установление значений по умолчанию (.data и .bss), в то время как другие пользовательские разделы не могут быть заполнены значениями по умолчанию, что приводит к переменным со значением init, не будет иметь никакого эффекта.
Чтобы быть независимым от такой проблемы, создайте функцию init для каждого модуля и используйте ее для установки значений по умолчанию для всех ваших переменных, например, так:
static int32_t a ; /* OK */
static int32_t b = 4 ; /* Wrong - this value may not be set at zero
if linker script&startup files are not properly handled */
void
my_module_init ( void ) {
a = 0 ;
b = 4 ;
}
void
my_func ( void ) {
/* 1 */
char a ; /* OK */
/* 2 */
char a , b ; /* OK */
/* 3 */
char a ;
char b ; /* Wrong, variable with char type already exists */
}
int
my_func ( void ) {
/* 1 */
my_struct_t my ; /* First custom structures */
my_struct_ptr_t * p ; /* Pointers too */
/* 2 */
uint32_t a ;
int32_t b ;
uint16_t c ;
int16_t g ;
char h ;
/* ... */
/* 3 */
double d ;
float f ;
}
typedef struct {
int a , b ;
} str_t ;
str_t s = {
. a = 1 ,
. b = 2 , /* Comma here */
}
/* Examples of "complex" structure, with or with missing several trailing commas, after clang-format runs the formatting */
static const my_struct_t my_var_1 = {
. type = TYPE1 ,
. type_data =
{
. type1 =
{
. par1 = 0 ,
. par2 = 1 , /* Trailing comma here */
}, /* Trailing comma here */
}, /* Trailing comma here */
};
static const my_struct_t my_var_2 = {. type = TYPE2 ,
. type_data = {
. type2 =
{
. par1 = 0 ,
. par2 = 1 ,
},
}}; /* Missing comma here */
static const my_struct_t my_var_3 = {. type = TYPE3 ,
. type_data = {. type3 = {
. par1 = 0 ,
. par2 = 1 ,
}}}; /* Missing 2 commas here */
/* No trailing commas - good only for small and simple structures */
static const my_struct_t my_var_4 = {. type = TYPE4 , . type_data = {. type4 = {. par1 = 0 , . par2 = 1 }}};
for
/* OK */
for ( size_t i = 0 ; i < 10 ; ++ i )
/* OK, if you need counter variable later */
size_t i ;
for ( i = 0 ; i < 10 ; ++ i ) {
if (...) {
break ;
}
}
if ( i == 10 ) {
}
/* Wrong */
size_t i ;
for ( i = 0 ; i < 10 ; ++ i ) ...
void
a ( void ) {
/* Avoid function calls when declaring variable */
int32_t a , b = sum ( 1 , 2 );
/* Use this */
int32_t a , b ;
b = sum ( 1 , 2 );
/* This is ok */
uint8_t a = 3 , b = 4 ;
}
char
, float
или double
, всегда используйте типы, объявленные в библиотеке stdint.h
, например. uint8_t
для unsigned 8-bit
и т. Д.stdbool.h
. Используйте 1
или 0
для true
или false
соответственно /* OK */
uint8_t status ;
status = 0 ;
/* Wrong */
#include <stdbool.h>
bool status = true;
true
, например. if (check_func() == 1)
, используйте if (check_func()) { ... }
NULL
значением void * ptr ;
/* ... */
/* OK, compare against NULL */
if ( ptr == NULL || ptr != NULL ) {
}
/* Wrong */
if ( ptr || ! ptr ) {
}
int32_t a = 0 ;
...
a ++ ; /* Wrong */
++ a ; /* OK */
for ( size_t j = 0 ; j < 10 ; ++ j ) {} /* OK */
size_t
для переменных длины или размераconst
для указателя, если функция не должна изменять память, указанную по pointer
const
для параметра или переменной функции, если он не должен быть изменен /* When d could be modified, data pointed to by d could not be modified */
void
my_func ( const void * d ) {
}
/* When d and data pointed to by d both could not be modified */
void
my_func ( const void * const d ) {
}
/* Not REQUIRED, it is advised */
void
my_func ( const size_t len ) {
}
/* When d should not be modified inside function, only data pointed to by d could be modified */
void
my_func ( void * const d ) {
}
void *
, не используйте uint8_t *
/*
* To send data, function should not modify memory pointed to by `data` variable
* thus `const` keyword is important
*
* To send generic data (or to write them to file)
* any type may be passed for data,
* thus use `void *`
*/
/* OK example */
void
send_data ( const void * data , size_t len ) { /* OK */
/* Do not cast `void *` or `const void *` */
const uint8_t * d = data ; /* Function handles proper type for internal usage */
}
void
send_data ( const void * data , int len ) { /* Wrong, not not use int */
}
sizeof
malloc
и free
функциями или если библиотека/проект предоставляет пользовательское распределение памяти, используйте ее реализацию /* OK */
#include <stdlib.h>
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 */
}
boolean
типboolean-treated
переменными с нулем или одним. Не использовать ( !
) Вместо этого size_t length = 5 ; /* Counter variable */
uint8_t is_ok = 0 ; /* Boolean-treated variable */
if ( length ) /* Wrong, length is not treated as boolean */
if ( length > 0 ) /* OK, length is treated as counter variable containing multi values, not only 0 or 1 */
if ( length == 0 ) /* OK, length is treated as counter variable containing multi values, not only 0 or 1 */
if ( is_ok ) /* OK, variable is treated as boolean */
if (! is_ok ) /* OK, -||- */
if ( is_ok == 1 ) /* Wrong, never compare boolean variable against 1! */
if ( is_ok == 0 ) /* Wrong, use ! for negative check */
/* comment */
для комментариев, даже для однострочного комментарияC++
с ключевым словом extern
в файле заголовкаstatic
force_redraw
. Не используйте forceRedraw
void *
, например. uint8_t* ptr = (uint8_t *)func_returning_void_ptr();
Поскольку void *
безопасно продвигается на любой другой тип указателяuint8_t* ptr = func_returning_void_ptr();
вместо<
и >
для стандартной библиотеки C, включайте файлы, например. #include <stdlib.h>
""
для пользовательских библиотек, например. #include "my_library.h"
uint8_t* t = (uint8_t*)var_width_diff_type
//
не допускаются. Всегда используйте /* comment */
, даже для однострочного комментария //This is comment (wrong)
/* This is comment (ok) */
space+asterisk
для каждой строки /*
* 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) */
12
отсеков ( 12 * 4
пространства) смещение при комментировании. Если утверждение больше, чем 12
отступов, сделайте выровненные комментированные 4-spaces
(примеры ниже) до следующего доступного отступления 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 */
}
_
/* OK */
void my_func ( void );
void myfunc ( void );
/* Wrong */
void MYFunc ( void );
void myFunc ();
/* 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 );
/* 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 );
/* OK */
int32_t
foo ( void ) {
return 0 ;
}
/* OK */
static const char *
get_string ( void ) {
return "Hello world!rn" ;
}
/* Wrong */
int32_t foo ( void ) {
return 0 ;
}
_
символом /* OK */
int32_t a ;
int32_t my_var ;
int32_t myvar ;
/* Wrong */
int32_t A ;
int32_t myVar ;
int32_t MYVar ;
type
void
foo ( void ) {
int32_t a , b ; /* OK */
char a ;
char b ; /* Wrong, char type already exists */
}
void
foo ( void ) {
int32_t a ;
a = bar ();
int32_t b ; /* Wrong, there is already executable statement */
}
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 */
}
/* OK */
char * a ;
/* Wrong */
char * a ;
char * a ;
/* OK */
char * p , * n ;
_
символом между словамиtypedef
Когда структура объявлена, она может использовать один из 3
различных вариантов:
_t
после своего имени. struct struct_name {
char * a ;
char b ;
};
_t
суффикс после своего имени. typedef struct {
char * a ;
char b ;
} struct_name_t ;
_t
для основного имени, и она должна содержать _t
суффикс после его имени для части Typedef. typedef struct struct_name { /* No _t */
char * a ;
char b ;
char c ;
} struct_name_t ; /* _t */
Примеры плохих деклараций и их предлагаемых исправлений
/* 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 ;
C99
/* OK */
a_t a = {
. a = 4 ,
. b = 5 ,
};
/* Wrong */
a_t a = { 1 , 2 };
_fn
/* 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 );
1
вложенное заявление1
размер отступления для каждого гнезда /* OK */
if ( c ) {
do_a ();
} else {
do_b ();
}
/* Wrong */
if ( c )
do_a ();
else
do_b ();
/* Wrong */
if ( c ) do_a ();
else do_b ();
if
или if-else-if
, else
должно быть в той же строке, что и закрывающая скобка первого оператора /* OK */
if ( a ) {
} else if ( b ) {
} else {
}
/* Wrong */
if ( a ) {
}
else {
}
/* Wrong */
if ( a ) {
}
else
{
}
do-while
, while
часть должна быть в той же линии, что и закрывающее скобки do
Part /* OK */
do {
int32_t a ;
a = do_a ();
do_b ( a );
} while ( check ());
/* Wrong */
do
{
/* ... */
} while ( check ());
/* Wrong */
do {
/* ... */
}
while ( check ());
if ( a ) {
do_a ();
} else {
do_b ();
if ( c ) {
do_c ();
}
}
if ( a ) do_b ();
else do_c ();
if ( a ) do_a (); else do_b ();
while
do-while
, или for
петли, должны включать в себя скобки /* OK */
while ( is_register_bit_set ()) {}
/* Wrong */
while ( is_register_bit_set ());
while ( is_register_bit_set ()) { }
while ( is_register_bit_set ()) {
}
for
, do-while
и т. Д.) while
(это может быть в случае встроенного программирования), используйте пустые однострочные кронштейны /* Wait for bit to be set in embedded hardware unit */
volatile uint32_t * addr = HW_PERIPH_REGISTER_ADDR ;
/* Wait bit 13 to be ready */
while ( * addr & ( 1 << 13 )) {} /* OK, empty loop contains no spaces inside curly brackets */
while ( * addr & ( 1 << 13 )) { } /* Wrong */
while ( * addr & ( 1 << 13 )) { /* Wrong */
}
while ( * addr & ( 1 << 13 )); /* Wrong, curly brackets are missing. Can lead to compiler warnings or unintentional bugs */
for
, do-while
, while
/* Not recommended */
int32_t a = 0 ;
while ( a < 10 ) {
.
..
...
++ a ;
}
/* Better */
for ( size_t a = 0 ; a < 10 ; ++ a ) {
}
/* Better, if inc may not happen in every cycle */
for ( size_t a = 0 ; a < 10 ; ) {
if (...) {
++ a ;
}
}
if
операции могут использоваться только для операций на назначении или функциональном вызове /* OK */
int a = condition ? if_yes : if_no ; /* Assignment */
func_call ( condition ? if_yes : if_no ); /* Function call */
switch ( condition ? if_yes : if_no ) {...} /* OK */
/* Wrong, this code is not well maintenable */
condition ? call_to_function_a () : call_to_function_b ();
/* Rework to have better program flow */
if ( condition ) {
call_to_function_a ();
} else {
call_to_function_b ();
}
case
break
в каждом case
или операторе default
/* OK, every case has single indent */
/* OK, every break has additional indent */
switch ( check ()) {
case 0 :
do_a ();
break ;
case 1 :
do_b ();
break ;
default :
break ;
}
/* Wrong, case indent missing */
switch ( check ()) {
case 0 :
do_a ();
break ;
case 1 :
do_b ();
break ;
default :
break ;
}
/* Wrong */
switch ( check ()) {
case 0 :
do_a ();
break ; /* Wrong, break MUST have indent as it is under case */
case 1 :
do_b (); /* Wrong, indent under case is missing */
break ;
default :
break ;
}
default
/* OK */
switch ( var ) {
case 0 :
do_job ();
break ;
default :
break ;
}
/* Wrong, default is missing */
switch ( var ) {
case 0 :
do_job ();
break ;
}
break
внутрь.case
switch ( a ) {
/* OK */
case 0 : {
int32_t a , b ;
char c ;
a = 5 ;
/* ... */
break ;
}
/* Wrong */
case 1 :
{
int32_t a ;
break ;
}
/* Wrong, break shall be inside */
case 2 : {
int32_t a ;
}
break ;
}
_
символом, за исключением случаев, когда они четко обозначены как функция, которая может быть в будущем заменен на регулярную функцию синтаксиса /* OK */
#define SQUARE ( x ) ((x) * (x))
/* Wrong */
#define square ( x ) ((x) * (x))
/* OK */
#define MIN ( x , y ) ((x) < (y) ? (x) : (y))
/* Wrong */
#define MIN ( x , y ) x < y ? x : y
/* Wrong */
#define MIN ( x , y ) (x) < (y) ? (x) : (y)
#define SUM ( x , y ) (x) + (y)
/* Imagine result of this equation using wrong SUM implementation */
int32_t x = 5 * SUM ( 3 , 4 ); /* Expected result is 5 * 7 = 35 */
int32_t x = 5 * ( 3 ) + ( 4 ); /* It is evaluated to this, final result = 19 which is not what we expect */
/* Correct implementation */
#define MIN ( x , y ) ((x) < (y) ? (x) : (y))
#define SUM ( x , y ) ((x) + (y))
do {} while (0)
typedef struct {
int32_t px , py ;
} point_t ;
point_t p ; /* Define new point */
/* Wrong implementation */
/* Define macro to set point */
#define SET_POINT ( p , x , y ) (p)->px = (x); (p)->py = (y) /* 2 statements. Last one should not implement semicolon */
SET_POINT ( & p , 3 , 4 ); /* Set point to position 3, 4. This evaluates to... */
( & p ) -> px = ( 3 ); ( & p ) -> py = ( 4 ); /* ... to this. In this example this is not a problem. */
/* Consider this ugly code, however it is valid by C standard (not recommended) */
if ( a ) /* If a is true */
if ( b ) /* If b is true */
SET_POINT ( & p , 3 , 4 ); /* Set point to x = 3, y = 4 */
else
SET_POINT ( & p , 5 , 6 ); /* Set point to x = 5, y = 6 */
/* Evaluates to code below. Do you see the problem? */
if ( a )
if ( b )
( & p ) -> px = ( 3 ); ( & p ) -> py = ( 4 );
else
( & p ) -> px = ( 5 ); ( & p ) -> py = ( 6 );
/* Or if we rewrite it a little */
if ( a )
if ( b )
( & p ) -> px = ( 3 );
( & p ) -> py = ( 4 );
else
( & p ) -> px = ( 5 );
( & p ) -> py = ( 6 );
/*
* Ask yourself a question: To which `if` statement does the `else` keyword belong?
*
* Based on first part of code, answer is straight-forward. To inner `if` statement when we check `b` condition
* Actual answer: Compilation error as `else` belongs nowhere
*/
/* Better and correct implementation of macro */
#define SET_POINT ( p , x , y ) do { (p)->px = (x); (p)->py = (y); } while (0) /* 2 statements. No semicolon after while loop */
/* Or even better */
#define SET_POINT ( p , x , y ) do { /* Backslash indicates statement continues in new line */
( p ) -> px = ( x );
( p ) -> py = ( y );
} while ( 0 ) /* 2 statements. No semicolon after while loop */
/* Now original code evaluates to */
if ( a )
if ( b )
do { ( & p ) -> px = ( 3 ); ( & p ) -> py = ( 4 ); } while ( 0 );
else
do { ( & p ) -> px = ( 5 ); ( & p ) -> py = ( 6 ); } while ( 0 );
/* Every part of `if` or `else` contains only `1` inner statement (do-while), hence this is valid evaluation */
/* To make code perfect, use brackets for every if-ifelse-else statements */
if ( a ) { /* If a is true */
if ( b ) { /* If b is true */
SET_POINT ( & p , 3 , 4 ); /* Set point to x = 3, y = 4 */
} else {
SET_POINT ( & p , 5 , 6 ); /* Set point to x = 5, y = 6 */
}
}
#ifdef
или #ifndef
. Используйте defined()
или !defined()
вместо этого #ifdef XYZ
/* do something */
#endif /* XYZ */
if/elif/else/endif
операторы /* 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
#if
/* OK */
#if defined( XYZ )
#if defined( ABC )
/* do when ABC defined */
#endif /* defined(ABC) */
#else /* defined(XYZ) */
/* Do when XYZ not defined */
#endif /* !defined(XYZ) */
/* Wrong */
#if defined( XYZ )
#if defined( ABC )
/* do when ABC defined */
#endif /* defined(ABC) */
#else /* defined(XYZ) */
/* Do when XYZ not defined */
#endif /* !defined(XYZ) */
Задокументированный код позволяет Doxygen разбирать и генерировать HTML/PDF/Latex, поэтому очень важно сделать это должным образом на ранней стадии проекта.
variables
, functions
и structures/enumerations
для doxygen, не используйте @
5x4
( 5
вкладок). Смещение от начала строки для текста /**
* brief Holds pointer to first entry in linked list
* Beginning of this text is 5 tabs (20 spaces) from beginning of line
*/
static
type_t * list ;
/**
* brief This is point struct
* note This structure is used to calculate all point
* related stuff
*/
typedef struct {
int32_t x ; /*!< Point X coordinate */
int32_t y ; /*!< Point Y coordinate */
int32_t size ; /*!< Point size.
Since comment is very big,
you may go to next line */
} point_t ;
/**
* brief Point color enumeration
*/
typedef enum {
COLOR_RED , /*!< Red color */
COLOR_GREEN , /*!< Green color */
COLOR_BLUE , /*!< Blue color */
} point_color_t ;
brief
и все параметры документацииin
или out
для ввода и вывода соответственноreturn
параметр, если он что -то возвращает. Это не применяется для void
функцийnote
или warning
:
между названием параметра и его описанием /**
* brief Sum `2` numbers
* param[in] a: First number
* param[in] b: Second number
* return Sum of input values
*/
int32_t
sum ( int32_t a , int32_t b ) {
return a + b ;
}
/**
* brief Sum `2` numbers and write it to pointer
* note This function does not return value, it stores it to pointer instead
* param[in] a: First number
* param[in] b: Second number
* param[out] result: Output variable used to save result
*/
void
void_sum ( int32_t a , int32_t b , int32_t * result ) {
* result = a + b ;
}
ref
чтобы указать, какое из них /**
* brief My enumeration
*/
typedef enum {
MY_ERR , /*!< Error value */
MY_OK /*!< OK value */
} my_enum_t ;
/**
* brief Check some value
* return ref MY_OK on success, member of ref my_enum_t otherwise
*/
my_enum_t
check_value ( void ) {
return MY_OK ;
}
NULL
) для констант или чисел /**
* brief Get data from input array
* param[in] in: Input data
* return Pointer to output data on success, `NULL` otherwise
*/
const void *
get_data ( const void * in ) {
return in ;
}
hideinitializer
Doxygen /**
* brief Get minimal value between `x` and `y`
* param[in] x: First value
* param[in] y: Second value
* return Minimal value between `x` and `y`
* hideinitializer
*/
#define MIN ( x , y ) ((x) < (y) ? (x) : (y))
file
и brief
описание, за которым следует пустая линия (при использовании doxygen) /**
* file template.h
* brief Template include file
*/
/* Here is empty line */
/**
* file template.h
* brief Template include file
*/
/*
* Copyright (c) year FirstName LASTNAME
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* This file is part of library_name.
*
* Author: FirstName LASTNAME <[email protected]>
*/
#ifndef
C++
ПроверкаC++
Проверкаextern
для глобальных переменных модуля в файле заголовка, определите их в исходном файле позже /* file.h ... */
#ifndef ...
extern int32_t my_variable; /* This is global variable declaration in header */
#endif
/* file.c ... */
int32_t my_variable; /* Actually defined in source */
Никогда не включайте .c
файлы в другой файл .c
.c
Файл должен сначала включать соответствующий файл .h
Не включайте частные объявления модуля в файл заголовка
Пример файла заголовка (без лицензии для примера)
/* License comes here */
#ifndef TEMPLATE_HDR_H
#define TEMPLATE_HDR_H
/* Include headers */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* File content here */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* TEMPLATE_HDR_H */
clang-format
поставляется с файлом всегда .clang-format
. Он может быть бесшовно интегрирован с большинством новейших технологий, включая VSCODE. Форматирование затем происходит на месте на каждом файле Сохранить.
https://code.visualstudio.com/docs/cpp/cpp-ide#_code-formatting
Astyle - это отличная часть программного обеспечения, которое может помочь в форматировании кода на основе конфигурации ввода.
Этот репозиторий содержит файл astyle-code-format.cfg
, который можно использовать с программным обеспечением AStyle
.
astyle --options="astyle-code-format.cfg" "input_path/*.c,*.h" "input_path2/*.c,*.h"
Конфигурация художественного стиля устарела и больше не обновляется
Репозиторий содержит файл eclipse-ext-kr-format.xml
, который можно использовать с на основе инструментов на основе Eclipse для установки параметров форматера.
Он основан на форматере K & R с модификациями для уважения выше правил. Вы можете импортировать его в настройках Eclipse, Preferences -> LANGUAGE -> Code Style -> Formatter
.