国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【正點原子STM32】C語言重點知識(配置MDK支持C99、位操作清零置一、帶參數(shù)的宏定義、頭文件的條件編譯和代碼條件編譯、關(guān)鍵字、結(jié)構(gòu)體指針、代碼規(guī)范)

這篇具有很好參考價值的文章主要介紹了【正點原子STM32】C語言重點知識(配置MDK支持C99、位操作清零置一、帶參數(shù)的宏定義、頭文件的條件編譯和代碼條件編譯、關(guān)鍵字、結(jié)構(gòu)體指針、代碼規(guī)范)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、stdint.h簡介

  • 配置MDK支持C99

二、位操作

  • 如何給寄存器某個位賦值(清零置一)

三、宏定義

  • 帶參數(shù)的宏定義

四、條件編譯

  • 頭文件的條件編譯和代碼條件編譯

五、extern聲明
六、類型別名(typedef)

  • 類型別名應(yīng)用

七、結(jié)構(gòu)體

  • 應(yīng)用舉例(定義&使用)
  • 應(yīng)用舉例(ST源碼,使用類型別名)

八、指針

  • 指針使用的兩大最常見問題

九、代碼規(guī)范

  • 其他規(guī)范

十、總結(jié)


【C語言】關(guān)鍵字

一、stdint.h簡介

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
stdint.hC 語言標(biāo)準(zhǔn)庫中的一個頭文件,它在 C99 標(biāo)準(zhǔn)中被引入,目的是提供更為可移植性的整數(shù)類型定義。這個頭文件定義了一組與位數(shù)相關(guān)的整數(shù)類型,例如有符號整數(shù)(integers)和無符號整數(shù)(unsigned integers),以確保在不同平臺上的整數(shù)類型的大小和范圍是一致的。

以下是 stdint.h 中定義的一些常見的整數(shù)類型:

  • int8_t:8 位有符號整數(shù)

  • int16_t:16 位有符號整數(shù)

  • int32_t:32 位有符號整數(shù)

  • int64_t:64 位有符號整數(shù)

  • uint8_t:8 位無符號整數(shù)

  • uint16_t:16 位無符號整數(shù)

  • uint32_t:32 位無符號整數(shù)

  • uint64_t:64 位無符號整數(shù)

此外,還有一些標(biāo)準(zhǔn)宏定義用于表示最小和最大的整數(shù)值,例如:

  • INT8_MIN, INT16_MIN, INT32_MIN, INT64_MIN:有符號整數(shù)的最小值
  • INT8_MAX, INT16_MAX, INT32_MAX, INT64_MAX:有符號整數(shù)的最大值
  • UINT8_MAX, UINT16_MAX, UINT32_MAX, UINT64_MAX:無符號整數(shù)的最大值

這些類型和宏的定義旨在提供可靠的整數(shù)大小和范圍,以便程序員可以編寫更加可移植的代碼,而不用擔(dān)心不同平臺上整數(shù)類型的差異。

在 MDK5.34 路徑下的 include 文件夾中,stdint.h 可能包含有適用于 ARM Cortex-M 微控制器的特定定義。這使得在嵌入式系統(tǒng)中使用 stdint.h 更加方便,因為可以根據(jù)具體的微控制器架構(gòu)來定義整數(shù)類型。

配置MDK支持C99

Options for Target 目標(biāo)選項 > C/C++ > C99 Mode
mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題

二、位操作

按位運算符、邏輯運算符
mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
位操作是一種對二進(jìn)制位進(jìn)行操作的方法,常用于處理底層硬件控制、優(yōu)化算法和處理位圖等場景。以下是常見的位操作運算符及其含義:

  1. &(按位與):

    • 對兩個二進(jìn)制數(shù)的每一位執(zhí)行邏輯與操作。結(jié)果中的每一位都是兩個數(shù)對應(yīng)位上的最小值。
    • 例如:1010 & 1100 = 1000
  2. |(按位或):

    • 對兩個二進(jìn)制數(shù)的每一位執(zhí)行邏輯或操作。結(jié)果中的每一位都是兩個數(shù)對應(yīng)位上的最大值。
    • 例如:1010 | 1100 = 1110
  3. ^(按位異或):

    • 對兩個二進(jìn)制數(shù)的每一位執(zhí)行邏輯異或操作。結(jié)果中的每一位都是兩個數(shù)對應(yīng)位上的不同值。
    • 例如:1010 ^ 1100 = 0110
  4. ~(按位取反):

    • 對一個二進(jìn)制數(shù)的每一位執(zhí)行邏輯取反操作,即將 0 變?yōu)?1,將 1 變?yōu)?0。
    • 例如:~1010 = 0101
  5. <<(左移):

    • 將一個二進(jìn)制數(shù)的所有位向左移動指定的位數(shù),右側(cè)補零。
    • 例如:1010 << 2 = 101000
  6. >>(右移):

    • 將一個二進(jìn)制數(shù)的所有位向右移動指定的位數(shù),左側(cè)根據(jù)符號位補零或補一(對于有符號整數(shù))。
    • 例如:1010 >> 2 = 10

這些位操作運算符在低級別的編程和嵌入式系統(tǒng)開發(fā)中經(jīng)常被使用,因為它們可以高效地操作二進(jìn)制數(shù)據(jù)。在處理寄存器、位掩碼和優(yōu)化算法時,位操作非常有用。
mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題

如何給寄存器某個位賦值(清零置一)

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
在 C 語言中,對寄存器的某個位進(jìn)行賦值通常使用位操作來實現(xiàn)。

常見的三種方式:

方法一:

temp &= 0xFFFFFFBF;  // 清除位6,將其置為0
temp |= 0x00000040;  // 將位6設(shè)置為1

這里使用了按位與運算 & 和按位或運算 |。首先,temp &= 0xFFFFFFBF; 將位6清零,然后 temp |= 0x00000040; 將位6設(shè)置為1。

方法二:

temp &= ~(1 << 6);   // 清除位6,將其置為0
temp |= 1 << 6;      // 將位6設(shè)置為1

這里使用了位掩碼和按位異或運算。temp &= ~(1 << 6); 使用位掩碼 ~(1 << 6) 清零位6,然后 temp |= 1 << 6; 將位6設(shè)置為1。

方法三:

temp ^= 1 << 6;      // 切換(翻轉(zhuǎn))位6的值

這里使用了按位異或運算 ^。temp ^= 1 << 6; 會將位6的值進(jìn)行翻轉(zhuǎn),即如果位6原來是0,則變成1;如果原來是1,則變成0。

這些方法的選擇通常取決于編碼的風(fēng)格和習(xí)慣,方法二是比較常見和推薦的一種方式,因為它直接使用位操作符,更加清晰和易讀。

三、宏定義

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
宏定義是 C 語言中的一種預(yù)處理指令,用于創(chuàng)建代碼中的簡單文本替換
通過宏定義,你可以為一個標(biāo)識符(宏名)指定一個特定的文本,在程序編譯前會進(jìn)行文本替換,提高了代碼的可讀性、易改性,同時也可以用于一些常量或者簡單表達(dá)式的定義。

你提到的宏定義的基本語法為:

#define 標(biāo)識符 字符串

其中,標(biāo)識符是宏定義的名字,字符串是與該標(biāo)識符相關(guān)聯(lián)的文本。這個文本可以是常數(shù)、表達(dá)式、格式串等。

下面是兩個宏定義的例子:

#define PI 3.14159

這個宏定義將標(biāo)識符 PI 關(guān)聯(lián)到常數(shù) 3.14159,在代碼中使用 PI 將被替換為 3.14159。

#define HSE_VALUE 8000000U

這個宏定義將標(biāo)識符 HSE_VALUE 關(guān)聯(lián)到常數(shù) 8000000U,在代碼中使用 HSE_VALUE 將被替換為 8000000U

在實際的程序開發(fā)中,宏定義經(jīng)常用于定義常數(shù)、配置參數(shù)、簡化代碼等方面。需要注意的是,在使用宏定義時,要確保宏名和關(guān)聯(lián)的文本不會與其他部分產(chǎn)生沖突,以免造成意外的替換。

帶參數(shù)的宏定義

宏定義為什么要使用do{……}while(0)形式
mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
帶參數(shù)的宏定義是 C 語言中一種強大的工具,允許在代碼中實現(xiàn)簡單的代碼生成。帶參數(shù)的宏定義的語法如下:

#define 宏名(參數(shù)列表) 代碼塊

其中,宏名是宏定義的名字,參數(shù)列表是傳遞給宏的參數(shù),代碼塊是宏的具體實現(xiàn)。

例子中定義了一個帶參數(shù)的宏 LED1(x),它接受一個參數(shù) x。這個宏用于控制 LED1 的狀態(tài),根據(jù)傳入的參數(shù) x 的值來設(shè)置 GPIO 的輸出狀態(tài)。

在宏定義中,使用了 do { ... } while(0) 結(jié)構(gòu)。這種結(jié)構(gòu)的目的是創(chuàng)建一個語句塊,盡管在 C 語言中并不需要這樣的結(jié)構(gòu),但在宏定義中使用它的好處在于可以確保宏在被調(diào)用時總是作為一個語句塊執(zhí)行。

這樣設(shè)計的原因是避免在宏的使用過程中受到語法的限制,例如:

if (condition)
    LED1(1);
else
    do_something_else();

如果沒有 do { ... } while(0) 結(jié)構(gòu),上面的代碼可能會因為缺少大括號而導(dǎo)致語法錯誤。使用這種結(jié)構(gòu),即使在 if 語句中使用宏,也能確保宏始終作為一個整體執(zhí)行,避免了潛在的錯誤。

總的來說,帶參數(shù)的宏定義是一種強大的代碼生成工具,但在使用時需要小心,確保宏定義的展開不會引發(fā)意外的行為。

四、條件編譯

【預(yù)處理命令】
mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
條件編譯是一種在編譯階段根據(jù)條件選擇性地包含或排除代碼的技術(shù)。在 C 語言中,條件編譯主要通過預(yù)處理指令來實現(xiàn)。以下是常用的條件編譯指令:

  1. #if:編譯預(yù)處理條件指令,類似于 if 語句,根據(jù)條件判斷是否編譯一段代碼。

    #if condition
        // code to be compiled if condition is true
    #endif
    
  2. #ifdef:判斷某個宏是否已被定義,如果宏已經(jīng)定義,則編譯相應(yīng)的代碼。

    #ifdef MACRO_NAME
        // code to be compiled if MACRO_NAME is defined
    #endif
    
  3. #ifndef:判斷某個宏是否未被定義,如果宏未定義,則編譯相應(yīng)的代碼。

    #ifndef MACRO_NAME
        // code to be compiled if MACRO_NAME is not defined
    #endif
    
  4. #elif:若前面的條件不滿足,則判定新的條件,類似于 else if。

    #if condition1
        // code to be compiled if condition1 is true
    #elif condition2
        // code to be compiled if condition2 is true
    #endif
    
  5. #else:若前面的條件不滿足,則執(zhí)行后面的語句,類似于 else。

    #if condition
        // code to be compiled if condition is true
    #else
        // code to be compiled if condition is false
    #endif
    
  6. #endif#if,#ifdef#ifndef 的結(jié)束標(biāo)志,標(biāo)識條件編譯塊的結(jié)束。

    #if condition
        // code to be compiled if condition is true
    #endif
    

這些條件編譯指令允許根據(jù)不同的條件選擇性地包含或排除代碼,從而實現(xiàn)在不同情況下編譯不同的代碼。這在處理不同平臺、不同配置或不同功能需求時非常有用。

頭文件的條件編譯和代碼條件編譯

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
頭文件的條件編譯和代碼條件編譯都是 C 語言中常用的技術(shù),用于在編譯時根據(jù)條件選擇性地包含或排除代碼。

頭文件的條件編譯:

#ifndef _LED_H
#define _LED_H

#include "./SYSTEM/sys/sys.h"

// 此處是頭文件的內(nèi)容

#endif
  • #ifndef _LED_H:如果宏 _LED_H 未被定義,則執(zhí)行以下代碼。
  • #define _LED_H:定義宏 _LED_H,表示頭文件已被包含,防止重復(fù)包含。
  • #include "./SYSTEM/sys/sys.h":包含其他頭文件或聲明。

這樣的結(jié)構(gòu)確保頭文件內(nèi)容只會在第一次被包含時有效,避免了重復(fù)包含的問題。

代碼條件編譯:

#if SYS_SUPPORT_OS
    // code
#endif
  • #if SYS_SUPPORT_OS:如果宏 SYS_SUPPORT_OS 的值為真(非零),則編譯以下代碼塊;否則,忽略該代碼塊。
  • // code:在條件滿足時編譯的代碼塊。

這樣的結(jié)構(gòu)可以根據(jù) SYS_SUPPORT_OS 宏的值來選擇性地編譯一段代碼。如果 SYS_SUPPORT_OS 宏為真,那么 // code 部分將被編譯;否則,該部分將被忽略。

總的來說,這兩種條件編譯技術(shù)在軟件開發(fā)中常用于處理不同的編譯環(huán)境、配置選項,以及實現(xiàn)代碼的可移植性和靈活性。

五、extern聲明

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
extern 關(guān)鍵字在 C 語言中用于聲明一個變量或函數(shù),表示該變量或函數(shù)是在其他文件中定義的,以便在當(dāng)前文件中引用。

示例中使用了 extern 來聲明變量和函數(shù):

  1. extern uint16_t g_usart_rx_sta;:這行代碼聲明了一個 uint16_t 類型的全局變量 g_usart_rx_sta,表示該變量在其他文件中定義,當(dāng)前文件中只是引用該變量。

  2. extern void delay_us(uint32_t nus);:這行代碼聲明了一個返回類型為 void、帶有一個 uint32_t 類型參數(shù)的函數(shù) delay_us。同樣,它表示該函數(shù)在其他文件中定義,當(dāng)前文件中只是引用該函數(shù)。

通過這樣的聲明,編譯器知道這些變量和函數(shù)在其他文件中定義,而在當(dāng)前文件中只是引用。在鏈接階段,鏈接器會負(fù)責(zé)將這些引用與實際的定義關(guān)聯(lián)起來。

這種機制在多個文件構(gòu)成的大型項目中非常有用,允許不同的源文件之間共享變量和函數(shù),從而實現(xiàn)模塊化開發(fā)。

六、類型別名(typedef)

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
typedef 是 C 語言中用于為現(xiàn)有數(shù)據(jù)類型創(chuàng)建新的名字(類型別名)的關(guān)鍵字。這可以用來簡化復(fù)雜的類型聲明,提高代碼的可讀性。

你的示例中使用了 typedef 來創(chuàng)建三個新的數(shù)據(jù)類型別名:

typedef unsigned char 		uint8_t;
typedef unsigned short int 	uint16_t;
typedef unsigned int 		uint32_t;

這里分別為 unsigned charunsigned short intunsigned int 這三種數(shù)據(jù)類型創(chuàng)建了新的名字 uint8_t、uint16_tuint32_t。這些新的名字可以在代碼中像普通的數(shù)據(jù)類型一樣使用。

例如,你可以使用這些類型別名來聲明變量:

uint8_t myByte;     // 使用 uint8_t 聲明變量
uint16_t myInt;     // 使用 uint16_t 聲明變量
uint32_t myLong;    // 使用 uint32_t 聲明變量

這樣做的好處是,使得代碼更具可讀性,并且如果以后需要更改底層的數(shù)據(jù)類型,只需要修改 typedef 部分而不需要修改整個代碼。這也有助于提高代碼的可維護性。

類型別名應(yīng)用

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
在示例中,使用了 typedef 來創(chuàng)建了一個名為 GPIO_TypeDef 的結(jié)構(gòu)體類型別名,使得在定義變量時更加簡潔、易讀。

首先,未使用 typedef 的結(jié)構(gòu)體定義:

struct GPIO_TypeDef
{
     __IO uint32_t   CRL;
     __IO uint32_t   CRH;
     // 其他成員...
};

struct GPIO_TypeDef gpiox;

在這個定義中,struct GPIO_TypeDef 是結(jié)構(gòu)體類型的標(biāo)簽,需要在每次聲明變量時都加上 struct 關(guān)鍵字。

為了避免每次都寫完整的類型,可以使用 typedef 來創(chuàng)建結(jié)構(gòu)體類型別名:

typedef struct
{
     __IO uint32_t   CRL;
     __IO uint32_t   CRH;
     // 其他成員...
} GPIO_TypeDef;

GPIO_TypeDef gpiox;

這樣,typedef 關(guān)鍵字允許你在定義結(jié)構(gòu)體的同時為其創(chuàng)建了一個類型別名 GPIO_TypeDef,在后續(xù)的代碼中可以直接使用 GPIO_TypeDef 來聲明變量,而不再需要寫 struct。

這種方式提高了代碼的可讀性,使得結(jié)構(gòu)體類型的使用更加簡潔,并且如果以后需要修改結(jié)構(gòu)體的定義,只需修改一處 typedef 部分而不會涉及到變量聲明的地方。

七、結(jié)構(gòu)體

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
結(jié)構(gòu)體(struct),它是由若干基本數(shù)據(jù)類型集合組成的一種自定義數(shù)據(jù)類型,也被稱為聚合類型。結(jié)構(gòu)體允許你將不同類型的數(shù)據(jù)組織在一起,形成一個新的數(shù)據(jù)類型。

以下是結(jié)構(gòu)體的基本定義語法:

struct 結(jié)構(gòu)體名
{
    成員列表;
} 變量名列表(可選);

你的例子中定義了一個名為 student 的結(jié)構(gòu)體,并聲明了兩個結(jié)構(gòu)體變量 stu1stu2

struct student
{
    char *name;     /* 姓名 */
    int num;        /* 學(xué)號 */
    int age;        /* 年齡 */
    char group;     /* 所在學(xué)習(xí)小組 */
    float score;    /* 成績 */
} stu1, stu2;

這個結(jié)構(gòu)體包含了五個成員:姓名(name)、學(xué)號(num)、年齡(age)、所在學(xué)習(xí)小組(group)和成績(score)。而后面的 stu1stu2 是兩個結(jié)構(gòu)體變量的實例。

你可以通過點操作符來訪問結(jié)構(gòu)體的成員,例如:

stu1.num = 12345;
stu1.age = 20;
stu1.score = 95.5;

這樣的定義和使用方式使得你能夠更靈活地組織和操作一組相關(guān)的數(shù)據(jù)。

應(yīng)用舉例(定義&使用)

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
示例定義了一個名為 student 的結(jié)構(gòu)體,然后聲明了兩個結(jié)構(gòu)體變量 stu3stu4。接著,對其中一個結(jié)構(gòu)體變量 stu3 進(jìn)行了賦值操作。這樣的結(jié)構(gòu)體定義和使用方式在實際編程中非常常見,用于組織和管理相關(guān)的數(shù)據(jù)。

#include <stdio.h>

// 定義結(jié)構(gòu)體
struct student
{
    char *name;      /* 姓名 */
    int num;         /* 學(xué)號 */
    int age;         /* 年齡 */
    char group;      /* 所在學(xué)習(xí)小組 */
    float score;     /* 成績 */
};

int main()
{
    // 聲明結(jié)構(gòu)體變量
    struct student stu3, stu4;

    // 對結(jié)構(gòu)體變量進(jìn)行賦值
    stu3.name = "張三";
    stu3.num = 1;
    stu3.age = 18;
    stu3.group = 'A';
    stu3.score = 80.9;

    // 輸出結(jié)構(gòu)體變量的值
    printf("姓名: %s\n", stu3.name);
    printf("學(xué)號: %d\n", stu3.num);
    printf("年齡: %d\n", stu3.age);
    printf("小組: %c\n", stu3.group);
    printf("成績: %.2f\n", stu3.score);

    return 0;
}

這個簡單的程序演示了結(jié)構(gòu)體的定義和使用。在實際的應(yīng)用中,結(jié)構(gòu)體通常用于表示實體的屬性,比如學(xué)生、員工等。通過定義結(jié)構(gòu)體,可以更清晰地組織數(shù)據(jù),并方便地對其進(jìn)行操作。在上述代碼中,你可以看到如何聲明結(jié)構(gòu)體、定義結(jié)構(gòu)體變量,并對結(jié)構(gòu)體成員進(jìn)行賦值和輸出。

應(yīng)用舉例(ST源碼,使用類型別名)

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
在這個例子中,我們看到了一種在嵌入式開發(fā)中常見的用法,即使用類型別名來定義一個結(jié)構(gòu)體,以方便后續(xù)使用。這段代碼摘自 STM32 HAL 庫中的 stm32f1xx_hal_gpio.h 頭文件,該頭文件定義了 STM32 系列微控制器的 GPIO 初始化結(jié)構(gòu)體類型。

typedef struct
{
  uint32_t Pin;      /* 引腳號 */
  uint32_t Mode;     /* 工作模式 */
  uint32_t Pull;     /* 上下拉 */
  uint32_t Speed;    /* IO 速度 */
} GPIO_InitTypeDef;

這里使用 typedef 創(chuàng)建了一個名為 GPIO_InitTypeDef 的類型別名,它是一個結(jié)構(gòu)體類型,包含了四個成員:PinMode、PullSpeed。這樣的類型別名使得在代碼中使用該結(jié)構(gòu)體更為方便,而不需要每次都寫完整的結(jié)構(gòu)體聲明。

在實際的 STM32 項目中,你可以使用這個結(jié)構(gòu)體類型來初始化 GPIO 引腳的配置,例如:

GPIO_InitTypeDef GPIO_InitStruct = {0};

// 初始化 GPIO 引腳配置
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

這段代碼演示了如何使用 GPIO_InitTypeDef 結(jié)構(gòu)體類型來初始化 GPIO 引腳的配置。這種方式使得代碼更為清晰,同時也提高了可讀性和可維護性。

八、指針

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
指針就是內(nèi)存的地址
指針變量是保存了指針的變量

以下是一些補充說明:

  1. 指針的定義和初始化:

    char *p_str = "This is a test!";
    

    這里定義了一個指向字符型數(shù)據(jù)的指針 p_str,并將其初始化為指向字符串常量 “This is a test!” 的首地址。這個指針可以用來訪問字符串的各個字符。

  2. 指針的解引用:

    *p_str;
    

    * 運算符用于解引用指針,取得指針?biāo)竷?nèi)存地址上的值。在這個例子中,*p_str 表示取得 p_str 所指向的字符串的第一個字符。

  3. 取地址運算符:

    &p_str;
    

    & 運算符用于取得變量的地址。在這個例子中,&p_str 表示取得 p_str 變量的地址。

  4. 指針變量的類型:

    int *p_int;
    

    這里定義了一個指向整數(shù)型數(shù)據(jù)的指針變量 p_int。指針變量的類型應(yīng)與所指向的數(shù)據(jù)類型相匹配。

指針是 C 語言中一個強大而靈活的特性,能夠提供直接的內(nèi)存訪問和更高效的數(shù)據(jù)處理。然而,正確地使用指針也需要謹(jǐn)慎,因為錯誤的指針操作可能導(dǎo)致程序崩潰或產(chǎn)生難以調(diào)試的 bug。
mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
在這個例子中,buf 是一個包含 5 個 uint8_t 類型元素的數(shù)組,而 p_buf 是指向 buf 數(shù)組首元素的指針。下面解釋每個操作的效果:

uint8_t buf[5] = {1, 3, 5, 7, 9};
uint8_t *p_buf = buf;

*p_buf = 10;  // 修改 buf[0] 的值為 10
// 此時 buf 數(shù)組變?yōu)?{10, 3, 5, 7, 9}

p_buf[0] = 20;  // 修改 buf[0] 的值為 20
// 此時 buf 數(shù)組變?yōu)?{20, 3, 5, 7, 9}

p_buf[1] = 30;  // 修改 buf[1] 的值為 30
// 此時 buf 數(shù)組變?yōu)?{20, 30, 5, 7, 9}

p_buf++;  // 將指針 p_buf 移動到下一個元素,即 buf[2]

*p_buf = 40;  // 修改 buf[2] 的值為 40
// 此時 buf 數(shù)組變?yōu)?{20, 30, 40, 7, 9}

p_buf[0] = 50;  // 修改 buf[2] 的值為 50
// 此時 buf 數(shù)組變?yōu)?{20, 30, 50, 7, 9}

這個例子演示了指針和數(shù)組的關(guān)系。指針 p_buf 指向數(shù)組 buf 的首元素,通過指針操作可以修改數(shù)組中相應(yīng)位置的值。每次對指針的操作都會影響到指針指向的位置。

指針使用的兩大最常見問題

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
兩大指針使用常見問題是非常重要的,確保正確分配內(nèi)存并避免越界訪問對于程序的穩(wěn)定性和安全性至關(guān)重要。

1. 未分配(申請)內(nèi)存就用

在這種情況下,指針沒有被正確初始化,試圖通過未分配內(nèi)存的指針進(jìn)行寫操作可能導(dǎo)致不可預(yù)測的結(jié)果。正確的做法是先分配足夠的內(nèi)存,然后再使用指針。

char *p_buf = (char *)malloc(sizeof(char) * 3);  // 分配內(nèi)存
if (p_buf != NULL) {
    p_buf[0] = 100;
    p_buf[1] = 120;
    p_buf[2] = 150;
    // 使用 p_buf
    free(p_buf);  // 釋放內(nèi)存
}

2. 越界使用

越界訪問指的是嘗試訪問數(shù)組或分配內(nèi)存之外的內(nèi)存區(qū)域。這可能導(dǎo)致程序崩潰或者產(chǎn)生不可預(yù)測的行為。正確的做法是確保指針在合法的范圍內(nèi)進(jìn)行訪問。

uint8_t buf[5] = {1, 3, 5, 7, 9};
uint8_t *p_buf = buf;

// 正確的訪問
for (int i = 0; i < 5; i++) {
    p_buf[i] = p_buf[i] + 10;
}

// 錯誤的越界訪問
// p_buf[5] = 200;  // 這里越界了,是錯誤的操作

總體而言,在使用指針時,始終要確保正確地分配了內(nèi)存,并在訪問數(shù)組或者其他數(shù)據(jù)結(jié)構(gòu)時保持越界訪問的風(fēng)險最小。

九、代碼規(guī)范

《嵌入式單片機 C代碼規(guī)范與風(fēng)格.pdf》
mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
遵循這樣的代碼規(guī)范可以提高代碼的可讀性和可維護性。下面是一些簡要的解釋和例子,以更清晰地說明規(guī)范:

  1. 小寫字母和駝峰命名法:

    int my_variable;
    void myFunction() {
        // 函數(shù)體
    }
    
  2. Doxygen 風(fēng)格注釋:

    /**
     * @brief 這是一個函數(shù)的簡要說明
     * @param 參數(shù)1 描述參數(shù)1
     * @param 參數(shù)2 描述參數(shù)2
     * @return 返回值說明
     */
    int myFunction(int param1, int param2) {
        // 函數(shù)體
    }
    
  3. 使用空格進(jìn)行對齊:

    if (condition) {
        // if 語句塊
    } else {
        // else 語句塊
    }
    
  4. 函數(shù)之間留有一個空行:

    void function1() {
        // 函數(shù)體
    }
    
    void function2() {
        // 函數(shù)體
    }
    
  5. 獨立程序塊之間有一個空行:

    // 程序塊1
    
    // 程序塊2
    
  6. 全局變量和指針命名:

    int g_global_variable;
    int *p_global_pointer;
    
  7. 語句單獨占一行,使用大括號:

    if (condition) {
        // if 語句塊
    } else {
        // else 語句塊
    }
    
    for (int i = 0; i < 10; i++) {
        // for 循環(huán)體
    }
    

以上規(guī)范是很好的實踐,可以提高代碼的一致性和可讀性,使得代碼更容易理解和維護。

其他規(guī)范

  1. 宏定義命名規(guī)范:

    #define MAX_BUFFER_SIZE 256
    

    使用大寫字母和下劃線,確保宏定義的可讀性和清晰性。

  2. 枚舉命名規(guī)范:

    enum Color {
        RED,
        GREEN,
        BLUE
    };
    

    使用大寫字母,枚舉成員使用大寫字母,用下劃線分隔。

  3. 文件命名規(guī)范:

文件名一般使用小寫字母,可以用下劃線或駝峰命名法。文件名應(yīng)該清晰地反映文件的內(nèi)容。

  1. 局部變量命名規(guī)范:
void myFunction() {
    int local_variable;
    // 函數(shù)體
}

使用小寫字母和駝峰命名法。

  1. 避免使用全局變量:

    盡量避免使用全局變量,尤其是在不同模塊之間共享全局變量。推薦使用函數(shù)參數(shù)和返回值來傳遞信息。

  2. 避免過長的函數(shù)和復(fù)雜的嵌套:

    函數(shù)應(yīng)該足夠簡潔,一個函數(shù)應(yīng)該完成一個特定的任務(wù)。過長的函數(shù)和復(fù)雜的嵌套結(jié)構(gòu)會降低代碼的可讀性。

  3. 常量命名規(guī)范:

    const int MAX_RETRY_COUNT = 5;
    

    使用大寫字母和下劃線,以便清晰地區(qū)分常量。

  4. 錯誤處理和日志記錄:

    錯誤處理應(yīng)該及時和清晰,對于日志記錄,使用合適的級別,確保日志信息對于調(diào)試和問題追蹤是有用的。

  5. 一次只做一件事(Single Responsibility Principle):

    每個函數(shù)和模塊應(yīng)該有一個清晰的目標(biāo),并只負(fù)責(zé)完成這個目標(biāo)。這有助于提高代碼的可維護性和可測試性。

這些規(guī)范可以根據(jù)團隊的具體需求進(jìn)行調(diào)整,但保持一致性和清晰性是至關(guān)重要的。

十、總結(jié)

mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題
mdk int64,STM32,配置MDK支持C99,位操作寄存器位賦值(清零置一),宏定義使用do while形式,頭文件的條件編譯和代碼條件編譯,extern關(guān)鍵字,類型別名typedef,指針最常見的問題文章來源地址http://www.zghlxwxcb.cn/news/detail-825926.html

到了這里,關(guān)于【正點原子STM32】C語言重點知識(配置MDK支持C99、位操作清零置一、帶參數(shù)的宏定義、頭文件的條件編譯和代碼條件編譯、關(guān)鍵字、結(jié)構(gòu)體指針、代碼規(guī)范)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包