يصف هذا المستند نمط رمز C الذي يستخدمه Tilen Majerle في مشاريعه ومكتباته.
لنبدأ بالاقتباس من موقع Gnome Developer.
القاعدة الأكثر أهمية عند كتابة رمز هي: تحقق من الكود المحيط وحاول تقليده .
بصفته أحد المشاريع ، من المفترض أن تتلقى تصحيحًا واضحًا في نمط ترميز مختلف للرمز المحيط. هذا غير محترم ، مثل شخص ما يدخل في منزل نظيف بدون نظيف مع أحذية موحلة.
لذلك ، أيا كان ما يوصي به هذا المستند ، إذا كان هناك رمز مكتوب بالفعل وأنت تقوم بتصحيحه ، حافظ على نمطه الحالي متسقًا حتى لو لم يكن أسلوبك المفضل.
يأتي VSCODE مع أداة clang-format
التي تم تثبيتها مسبقًا (جزء من حزمة LLVM) والتي تم تصميمها لمساعدة المطورين على أداة التنسيق التلقائي أثناء تطوير الكود.
على هذا النحو ، فإنه يسمح للمستخدمين بتنسيق رمز في تغيير الملف (وحفظه). عند حفظ الملف ، سيحاول VSCode استدعاء clang-format وتنسيق الكود. قواعد الاستخدام في ملف .clang-format
. إذا لم يتمكن Clang-Format من العثور على القواعد الموجودة في مسار الملف الحالي ، فسيتم تصل إلى الجذر ، حتى يتم العثور على واحدة. إذا كان لا يوجد شيء متاح ، فسيتم استخدام القواعد الافتراضية.
يحتوي هذا المستودع دائمًا على ملف .clang-format
مع قواعد مطابقة للقواعد الموضحة. يمكنك وضع المجلد في الجذر أو مشروعك أو حتى في جذر مشاريع تطوير البرمجيات -> استخدم ملفًا واحدًا للجميع!
يجب تمكين بعض التكوينات:
يجب أن لا ، يجب ألا يتم تفسير الكلمات الرئيسية ، يجب ألا تكون مطلوبة ، يجب ألا ، يجب ، لا ينبغي ، الموصى بها ، غير الموصى بها ، مايو ، واختيار في هذا المستند كما هو موضح في BCP 14 [RFC2119] [RFC8174]
فيما يلي مدرج قواعد عامة أكثر وضوحًا وهامة. يرجى التحقق منها بعناية قبل متابعة فصول أخرى.
clang-format
مع ملف التنسيق المرفق لهذا المستودع (الإصدار 15.x
هو الحد الأدنى)C11
Standard4
مسافات لكل مستوى مسافة بادئة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_
للوظائف الداخلية للمكتبة ، ولا ينبغي استخدامها بواسطة تطبيق المستخدم أثناء استخدامها عبر الوحدات الداخلية للمكتبة المختلفة_
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 */
في الأنظمة المضمنة ، من الشائع جدًا أن تنتشر ذكريات ذاكرة الوصول العشوائي عبر مواقع الذاكرة المختلفة في النظام. سرعان ما يصبح من الصعب التعامل مع جميع الحالات ، خاصةً عندما يعلن المستخدم أقسام ذاكرة الوصول العشوائي المخصصة. يعد برنامج STARTUP SCRIPT مسؤولاً لضبط القيم الافتراضية (.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
Standard أو إذا كانت المكتبة/المشروع توفر تخصيص ذاكرة مخصصة ، استخدم تنفيذه /* 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 ()) {
}
while
(أو for
، do-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
/**
* 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++
Checkextern
لمتغيرات الوحدة العالمية في ملف الرأس ، وتحديدها في الملف المصدر لاحقًا /* 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
.