freeRTOS核心學習筆記(1)-程式設計標準

mwzdouks發表於2020-07-26

在開始具體的學習之前,你應該先了解freeRTOS的程式設計標準.這能夠方便你在接下來的閱讀中快速的瞭解一些內容
的基本資訊,並方便記憶.此外,良好的程式設計風格也是工作效率的保障.
你可以在https://www.freertos.org/FreeRTOS-Coding-Standard-and-Style-Guide.html中找到英文的原文資訊.

儘管此前有人翻譯過這份文件,但釋出時間在很早以前,一些標準已經發生了改變.這裡按照此前翻譯的思路根據官方文件進行了更新和修訂.

程式設計標準(Coding Standard)

FreeRTOS程式碼遵循MISRA(Motor Industry Software Reliability Association)標準,但也有些區別.具體來說:

  • 為了效率,有兩個API函式擁有超過一個的出口點.
  • 使用了標準的C資料型別,而不是用typedef將其重定義.
  • 在建立任務時,程式碼會直接處理堆疊的棧頂和棧底地址.由於不同平臺的匯流排寬度並不相同,這就需要不可避免地對指標變數進行算數運算.
  • trace巨集的定義在預設情況為空,所以不會產生任何程式碼.因此,MISRA的遵從檢查其實是用假的巨集定義來執行的.
    此外,除了在stdint.h中,freeRTOS沒有使用任何C99標準中的語法和特性.在FreeRTOS/Source/include目錄下有一個名為stdint.readme的檔案,如果你想要使用stdint的資料型別的話,將它重新命名為stdint.h.

命名約定(Naming Conventions)

在freeRTOS的核心和示例中,按照以下約定命名:

  • 變數名
    • uint32_t 資料型別的變數的變數名以 ul 為字首.
    • uint16_t 資料型別的變數的變數名以 us 為字首.
    • uint8_t 資料型別的變數的變數名以 uc 為字首.
    • 非stdint資料型別的變數的變數名以 x 為字首.例如,BaseType_t TickType_t.
    • 無符號的非stdint資料型別的變數的變數名再新增一個額外的字首 u .例如,UBaseType_t(unsigned BaseType_t)資料型別的變數的變數名以 ux x為字首.
    • size_t 資料型別的變數的變數名也以 x 為字首.
    • 指標變數擁有一個額外的字首 p.例如,uint16_t的指標的變數名以 pus為字首.
    • 按照MISRA的標準,char資料型別只允許儲存ASCII字元,以 c 為字首.char的指標只允許指向ASCII字串,以 pc 為字首.
  • 函式名
    - 檔案的內部函式以prv為字首.
    - API函式以返回值型別為字首,參見前面變數名的命名約定(額外新增了v作為void返回值的字首).例如,vTaskDelete代表這個函式的返回值型別為void.
    - 函式名以所在檔名為開頭.例如,vTaskDelete函式在Task.c中定義.
  • 巨集
    - 巨集用所在檔名的一部分以小寫作為字首.例如,configUSE_PRESSMPTIONFreeRTOSConfig.h中定義.
    - 巨集的其餘部分用大寫字母,用下劃線分割.

資料型別

除了以下例外,只使用了stdint和freeRTOS自己定義的資料型別:

  • 按照MISRA的標準,char資料型別只允許儲存ASCII字元.
  • 按照MISRA的標準,char的指標只指向ASCII字串.

為每種介面,定義了4種資料型別:

  • TickType_t
    如果configUSE_16_BIT_TICKS是真值,那麼TickType_t為16-bit.否則則是32-bit.
  • BaseType_t
    該資料型別定義了一個平臺下效率最高的原生資料型別.例如,在32位的平臺下,BaseType_t將被定義為32-bit的資料型別.
    此外,如果BaseType_t被定義為了char,必須注意一定要是有符號的資料型別.因為在作為函式的返回值時,需要使用負值來表示錯誤.
  • UBaseType_t
    無符號的UBaseType_t.
  • StackType_t
    用於在棧中儲存資料.儘管存在例外,但通常,在16-bit平臺下該資料型別為16-bit,而在32-bit平臺下為32-bit.

程式設計風格

  • 縮排
    使用Tab縮排,一個Tab等於4個空格.
  • 註釋
    註釋不能超過80行,除非用來描述一個引數.
    不使用C++風格的註釋(//).
  • 佈局
    佈局和格式按照以下程式碼示例.
/* Library includes come first… */
#include <stdlib.h>
/* …followed by FreeRTOS includes… */
#include “FreeRTOS.h”
/* …followed by other includes. */
#include “HardwareSpecifics.h”
/* #defines comes next, bracketed where possible. */
#define A_DEFINITION	( 1 )

/*
 * Static (file private) function prototypes appear next, with comments
 * in this style – with each line starting with a ‘*’.
 */
static void prvAFunction( uint32_t ulParameter );

/* File scope variables are the last thing before the function definitions.
Comments for variables are in this style (without each line starting with
a ‘*’). */
static BaseType_t xMyVariable;

/* The following separate is used after the closing bracket of each function,
with a blank line following before the start of the next function definition. */

/*———————————————————–*/

void vAFunction( void )
{
    /* Function definition goes here – note the separator after the closing
    curly bracket. */
}
/*———————————————————–*/

static UBaseType_t prvNextFunction( void )
{
    /* Function definition goes here. */
}
/*———————————————————–*/

File Layout

/* Function names are always written on a single line, including the return
type.  As always, there is no space before the opening parenthesis.  There
is a space after an opening parenthesis.  There is a space before a closing
parenthesis.  There is a space after each comma.  Parameters are given
verbose, descriptive names (unlike this example!).  The opening and closing
curly brackets appear on their own lines, lined up underneath each other. */
void vAnExampleFunction( long lParameter1, unsigned short usParameter2 )
{
/* Variable declarations are not indented. */
uint8_t ucByte;

    /* Code is indented.  Curly brackets are always on their own lines
    and lined up underneath each other. */
    for( ucByte = 0U; ucByte < fileBUFFER_LENGTH; ucByte++ )
    {
        /* Indent again. */
    }
}

/* For, while, do and if constructs follow a similar pattern.  There is no
space before the opening parenthesis.  There is a space after an opening
parenthesis.  There is a space before a closing parenthesis.  There is a
space after each semicolon (if there are any).  There are spaces before and
after each operator.  No reliance is placed on operator precedence –
parenthesis are always used to make precedence explicit.  Magic numbers,
other than zero, are always replaced with a constant or #defined constant.
The opening and closing curly brackets appear on their own lines. */
for( ucByte = 0U; ucByte < fileBUFFER_LENGTH; ucByte++ )
{
}

while( ucByte < fileBUFFER_LENGTH )
{
}

/*  There must be no reliance on operator precedence – every condition in a
multi-condition decision must uniquely be bracketed, as must all
sub-expressions. */
if( ( ucByte < fileBUFFER_LENGTH ) && ( ucByte != 0U ) )
{
    /* Example of no reliance on operator precedence! */
    ulResult = ( ( ulValue1 + ulValue2 ) – ulValue3 ) * ulValue4;
}

/* Conditional compilations are laid out and indented as per any
other code. */
#if( configUSE_TRACE_FACILITY == 1 )
{
    /* Add a counter into the TCB for tracing only. */
    pxNewTCB->uxTCBNumber = uxTaskNumber;
}
#endif

A space is placed after an opening square bracket, and before a closing
square bracket. 
ucBuffer[ 0 ] = 0U;
ucBuffer[ fileBUFFER_LENGTH – 1U ] = 0U;

Formatting of C Constructs

相關文章