이 문서는 Tilen Majerle이 그의 프로젝트 및 도서관에서 사용한 C 코드 스타일에 대해 설명합니다.
그놈 개발자 사이트의 견적부터 시작하겠습니다.
코드를 작성할 때 가장 중요한 단일 규칙은 다음과 같습니다. 주변 코드를 확인하고 모방하십시오 .
관리자로서 주변 코드와 다른 코딩 스타일의 패치를받는 것은 실망 스럽습니다. 이것은 진흙 투성이의 신발을 가진 흠없는 청소 집에 들어가는 사람처럼 무례합니다.
따라서이 문서가 권장하는 것은 이미 작성된 코드가 있고 패치하는 경우 가장 좋아하는 스타일이 아니더라도 현재 스타일을 일관성있게 유지하십시오.
VSCODE에는 코드 개발 중에 자동 형식 도구를 사용하는 개발자를 돕기 위해 설계된 LLVM 패키지의 일부)가 사전 설치된 clang-format
도구 (LLVM 패키지의 일부)가 함께 제공됩니다.
따라서 사용자는 파일 변경 (및 저장)에서 코드를 포맷 할 수 있습니다. 파일이 저장되면 VScode는 Clang-Format을 호출하고 코드를 형식화하려고합니다. 사용할 규칙은 .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 */
__
또는 _
접두사를 사용하지 마십시오. 이것은 C 언어 자체를 위해 예약되어 있습니다prv_
이름 접두사를 선호하십시오libname_int_
또는 libnamei_
접두사를 선호하십시오. 다른 라이브러리 내부 모듈에서 사용해야하는 동안 사용자 애플리케이션에서 사용해서는 안됩니다._
옵션 밑줄이있는 변수/함수/유형에 소문자 만 사용하십시오.for
, 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 */
임베디드 시스템에서는 램 메모리가 시스템의 다른 메모리 위치에 흩어져있는 것이 매우 일반적입니다. 특히 사용자가 사용자 정의 RAM 섹션을 선언 할 때 모든 사례를 처리하는 것은 빠르게 까다로워집니다. 스타트 업 스크립트는 기본값 (.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
라이브러리에서 선언 된 유형을 사용합니다. unsigned 8-bit
등의 uint8_t
등stdbool.h
라이브러리를 사용하지 마십시오. true
또는 false
에 각각 1
또는 0
사용하십시오 /* 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
사용하십시오pointer
가리키는 메모리를 수정하지 않아야하는 경우 항상 포인터에 const
사용하십시오.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
Functions에서 동적 메모리 할당을 사용하거나 Library/Project가 사용자 정의 메모리 할당을 제공하는 경우 구현을 사용하십시오. /* 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
유형으로 취급되는 경우를 제외하고 항상 변수를 0과 비교하십시오.boolean-treated
변수를 0 또는 1과 비교하지 마십시오. 대신 ( !
)를 사용하십시오 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 */
댓글, 심지어 단일 라인 댓글조차도extern
키워드와 함께 항상 C++
수표를 포함시킵니다.static
인 경우에도 doxygen 지원 주석을 포함해야합니다.force_redraw
. forceRedraw
사용하지 마십시오void *
를 반환하지 않는 기능을하지 마십시오. uint8_t* ptr = (uint8_t *)func_returning_void_ptr();
void *
는 다른 포인터 유형으로 안전하게 홍보됩니다.uint8_t* ptr = func_returning_void_ptr();
대신에<
>
사용합니다. #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
포함해서는 안되며 typedef 부품의 이름 뒤에 _t
접미사를 포함 해야합니다 . 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
진술에 대해 단일 계약을 추가하십시오case
또는 default
문서에서 break
문장에 추가 단일 계약을 사용하십시오. /* 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
와 같은 다른 doxygen 키워드를 포함 할 수 있습니다.:
매개 변수 이름과 설명 사이 /**
* 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
에 대한 Doxygen 주석이 포함되어야하며 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
도구의 입력 구성 인 Always-to-Date .clang-format
파일이 함께 제공됩니다. VSCODE를 포함한 대부분의 최신 테크노 IDE와 완벽하게 통합 될 수 있습니다. 그런 다음 서식은 각 파일 저장의 지점에서 발생합니다.
https://code.visualstudio.com/docs/cpp/cpp-ide#_code-formatting
Astyle은 입력 구성을 기반으로 코드를 형식화하는 데 도움이되는 훌륭한 소프트웨어입니다.
이 저장소에는 AStyle
소프트웨어와 함께 사용할 수있는 astyle-code-format.cfg
파일이 포함되어 있습니다.
astyle --options="astyle-code-format.cfg" "input_path/*.c,*.h" "input_path2/*.c,*.h"
예술적 스타일 구성은 더 이상 사용되지 않으며 더 이상 업데이트되지 않습니다
저장소에는 eclipse-ext-kr-format.xml
파일이 포함되어 있으며 Eclipse 기반 툴체인과 함께 Formatter 옵션을 설정할 수 있습니다.
위의 규칙을 존중하기 위해 수정 된 K & R Formatter를 기반으로합니다. Eclipse 설정, Preferences -> LANGUAGE -> Code Style -> Formatter
탭 내에서 가져올 수 있습니다.