首頁 後端開發 C++ 可重複使用元件庫:簡化目標之間的遷移

可重複使用元件庫:簡化目標之間的遷移

Dec 08, 2024 pm 09:51 PM

Reusable Component Libraries: Simplifying Migration Between Targets

使用微控制器或目標本身外部的元件進行操作是韌體開發的常態。因此,了解如何為他們開發庫至關重要。這些庫允許我們與它們互動並交換資訊或命令。然而,在遺留程式碼或學生(或非學生)的程式碼中,經常會發現這些與元件的互動是直接在應用程式程式碼中完成的,或者即使放在單獨的檔案中,這些互動本質上也是如此與目標綁定。

讓我們來看看 STMicroelectronics STM32F401RE 應用程式中 Bosch BME280 溫度、濕度和壓力感測器的程式庫開發的一個糟糕範例。在範例中,我們要初始化組件並每 1 秒讀取一次溫度。 (在範例程式碼中,我們將省略STM32CubeMX/IDE產生的所有“噪音”,例如各種時鐘和周邊的初始化,或者諸如USER CODE BEGIN或USER CODE END之類的註解。)

#include "i2c.h"
#include <stdint.h>

int main(void)
{
    uint8_t  idx           = 0U;
    uint8_t  tx_buffer[64] = {0};
    uint8_t  rx_buffer[64] = {0};
    uint16_t dig_temp1     = 0U;
    int16_t  dig_temp2     = 0;
    int16_t  dig_temp3     = 0;

    MX_I2C1_Init();

    tx_buffer[idx++] = 0b10100011;

    HAL_I2C_Mem_Write(&hi2c1, 0x77U << 1U, 0xF4U, 1U,
                      tx_buffer, 1U, 200U);

    HAL_I2C_Mem_Read(&hi2c1, 0x77U << 1U, 0x88U, 1U,
                     rx_buffer, 6U, 200U);

    dig_temp1 = ((uint16_t)rx_buffer[0]) |
                (((uint16_t)rx_buffer[1]) << 8U);

    dig_temp2 = (int16_t)(((uint16_t)rx_buffer[2]) |
                          (((uint16_t)rx_buffer[3]) << 8U));

    dig_temp3 = (int16_t)(((uint16_t)rx_buffer[4]) |
                          (((uint16_t)rx_buffer[5]) << 8U));

    while (1)
    {
        float   temperature = 0.0f;
        int32_t adc_temp    = 0;
        int32_t t_fine      = 0;
        float   var1        = 0.0f;
        float   var2        = 0.0f;

        HAL_I2C_Mem_Read(&hi2c1, 0x77U << 1U, 0xFAU, 1U,
                         rx_buffer, 3U, 200U);

        adc_temp =
            (int32_t)((((uint32_t)rx_buffer[0]) << 12U) |
                      (((uint32_t)rx_buffer[1]) << 4U) |
                      (((uint32_t)rx_buffer[2]) >> 4U));

        var1 = (((float)adc_temp) / 16384.0f -
                ((float)dig_temp1) / 1024.0f) *
               ((float)dig_temp2);
        var2 = ((((float)adc_temp) / 131072.0f -
                 ((float)dig_temp1) / 8192.0f) *
                (((float)adc_temp) / 131072.0f -
                 ((float)dig_temp1) / 8192.0f)) *
               ((float)dig_temp3);

        t_fine = (int32_t)(var1 + var2);

        temperature = ((float)t_fine) / 5129.0f;

        // Temperature available for the application.
    }
}
登入後複製
登入後複製
登入後複製
登入後複製

基於這個例子,我們可以提出一系列問題:如果我需要更改目標(無論是由於庫存短缺、想要降低成本,還是只是開發使用相同組件的另一個產品),會發生什麼?如果系統中有多個相同類型的元件,會發生什麼情況?如果另一個產品使用相同的組件會發生什麼?如果我還沒有硬件,如何測試我的開發(這是專業領域中非常常見的情況,韌體和硬體開發階段經常在過程中的某些點重疊)?

對於前三個問題,答案是編輯程式碼,是否在切換目標時完全更改它,複製現有程式碼以與相同類型的附加元件一起操作,或者為目標實現相同的程式碼其他項目/產品。在最後一個問題中,如果沒有硬體執行程式碼,就無法測試程式碼。這意味著只有硬體完成後我們才能開始測試程式碼並開始修復韌體開發本身固有的錯誤,從而延長產品開發時間。這就提出了引發這篇文章的問題:是否可以為獨立於目標並允許重複使用的元件開發庫?答案是肯定的,這就是我們將在這篇文章中看到的內容。

將庫與目標隔離

為了將庫與目標隔離,我們將遵循兩條規則:1)我們將在其自己的編譯單元中實現庫,即它自己的文件,2)不會引用任何特定於目標的標頭或函數。我們將透過為 BME280 實作一個簡單的函式庫來示範這一點。首先,我們將在專案中建立一個名為 bme280 的資料夾。在 bme280 資料夾中,我們將建立以下檔案:bme280.c、bme280.h 和 bme280_interface.h。澄清一下,不,我沒有忘記將檔案命名為 bme280_interface.c。該文件不會成為庫的一部分。

我通常會將庫資料夾放在 Application/lib/ 中。

bme280.h 檔案將聲明我們的庫中可用的所有函數,供我們的應用程式呼叫。另一方面,bme280.c 檔案將實作這些函數的定義,以及函式庫可能包含的任何輔助函數和私有函數。那麼,bme280_interface.h 檔案包含什麼內容呢?好吧,無論我們的目標是什麼,都需要以一種或另一種方式與 BME280 組件進行通訊。在這種情況下,BME280 支援 SPI 或 I2C 通訊。在這兩種情況下,目標必須能夠讀取組件位元組並將其寫入組件。 bme280_interface.h 檔案將聲明這些函數,以便可以從庫中呼叫它們。這些函數的定義將是與特定目標相關的唯一部分,如果我們將庫遷移到另一個目標,這將是我們唯一需要編輯的內容。

聲明庫 API

我們先在 bme280.h 檔案中宣告函式庫中的可用函數。

#include "i2c.h"
#include <stdint.h>

int main(void)
{
    uint8_t  idx           = 0U;
    uint8_t  tx_buffer[64] = {0};
    uint8_t  rx_buffer[64] = {0};
    uint16_t dig_temp1     = 0U;
    int16_t  dig_temp2     = 0;
    int16_t  dig_temp3     = 0;

    MX_I2C1_Init();

    tx_buffer[idx++] = 0b10100011;

    HAL_I2C_Mem_Write(&hi2c1, 0x77U << 1U, 0xF4U, 1U,
                      tx_buffer, 1U, 200U);

    HAL_I2C_Mem_Read(&hi2c1, 0x77U << 1U, 0x88U, 1U,
                     rx_buffer, 6U, 200U);

    dig_temp1 = ((uint16_t)rx_buffer[0]) |
                (((uint16_t)rx_buffer[1]) << 8U);

    dig_temp2 = (int16_t)(((uint16_t)rx_buffer[2]) |
                          (((uint16_t)rx_buffer[3]) << 8U));

    dig_temp3 = (int16_t)(((uint16_t)rx_buffer[4]) |
                          (((uint16_t)rx_buffer[5]) << 8U));

    while (1)
    {
        float   temperature = 0.0f;
        int32_t adc_temp    = 0;
        int32_t t_fine      = 0;
        float   var1        = 0.0f;
        float   var2        = 0.0f;

        HAL_I2C_Mem_Read(&hi2c1, 0x77U << 1U, 0xFAU, 1U,
                         rx_buffer, 3U, 200U);

        adc_temp =
            (int32_t)((((uint32_t)rx_buffer[0]) << 12U) |
                      (((uint32_t)rx_buffer[1]) << 4U) |
                      (((uint32_t)rx_buffer[2]) >> 4U));

        var1 = (((float)adc_temp) / 16384.0f -
                ((float)dig_temp1) / 1024.0f) *
               ((float)dig_temp2);
        var2 = ((((float)adc_temp) / 131072.0f -
                 ((float)dig_temp1) / 8192.0f) *
                (((float)adc_temp) / 131072.0f -
                 ((float)dig_temp1) / 8192.0f)) *
               ((float)dig_temp3);

        t_fine = (int32_t)(var1 + var2);

        temperature = ((float)t_fine) / 5129.0f;

        // Temperature available for the application.
    }
}
登入後複製
登入後複製
登入後複製
登入後複製

我們建立的函式庫將非常簡單,我們只會實作一個基本的初始化函數和另一個來取得溫度測量值。現在,我們來實作bme280.c檔案中的函數。

為了避免貼文過於冗長,我跳過了記錄功能的註解。這是這些評論所在的文件。如今有這麼多的人工智慧工具可用,沒有理由不記錄您的程式碼。

驅動程式API的實現

bme280.c 檔案的骨架如下:

#ifndef BME280_H_
#define BME280_H_

void  BME280_init(void);
float BME280_get_temperature(void);

#endif // BME280_H_
登入後複製
登入後複製
登入後複製

讓我們專注於初始化。如前所述,BME280 支援 I2C 和 SPI 通訊。在這兩種情況下,我們都需要初始化目標的適當週邊裝置(I2C 或 SPI),然後我們需要能夠透過它們發送和接收位元組。假設我們使用 I2C 通信,在 STM32F401RE 中它將是:

#include "i2c.h"
#include <stdint.h>

int main(void)
{
    uint8_t  idx           = 0U;
    uint8_t  tx_buffer[64] = {0};
    uint8_t  rx_buffer[64] = {0};
    uint16_t dig_temp1     = 0U;
    int16_t  dig_temp2     = 0;
    int16_t  dig_temp3     = 0;

    MX_I2C1_Init();

    tx_buffer[idx++] = 0b10100011;

    HAL_I2C_Mem_Write(&hi2c1, 0x77U << 1U, 0xF4U, 1U,
                      tx_buffer, 1U, 200U);

    HAL_I2C_Mem_Read(&hi2c1, 0x77U << 1U, 0x88U, 1U,
                     rx_buffer, 6U, 200U);

    dig_temp1 = ((uint16_t)rx_buffer[0]) |
                (((uint16_t)rx_buffer[1]) << 8U);

    dig_temp2 = (int16_t)(((uint16_t)rx_buffer[2]) |
                          (((uint16_t)rx_buffer[3]) << 8U));

    dig_temp3 = (int16_t)(((uint16_t)rx_buffer[4]) |
                          (((uint16_t)rx_buffer[5]) << 8U));

    while (1)
    {
        float   temperature = 0.0f;
        int32_t adc_temp    = 0;
        int32_t t_fine      = 0;
        float   var1        = 0.0f;
        float   var2        = 0.0f;

        HAL_I2C_Mem_Read(&hi2c1, 0x77U << 1U, 0xFAU, 1U,
                         rx_buffer, 3U, 200U);

        adc_temp =
            (int32_t)((((uint32_t)rx_buffer[0]) << 12U) |
                      (((uint32_t)rx_buffer[1]) << 4U) |
                      (((uint32_t)rx_buffer[2]) >> 4U));

        var1 = (((float)adc_temp) / 16384.0f -
                ((float)dig_temp1) / 1024.0f) *
               ((float)dig_temp2);
        var2 = ((((float)adc_temp) / 131072.0f -
                 ((float)dig_temp1) / 8192.0f) *
                (((float)adc_temp) / 131072.0f -
                 ((float)dig_temp1) / 8192.0f)) *
               ((float)dig_temp3);

        t_fine = (int32_t)(var1 + var2);

        temperature = ((float)t_fine) / 5129.0f;

        // Temperature available for the application.
    }
}
登入後複製
登入後複製
登入後複製
登入後複製

外圍設備初始化後,我們需要初始化元件。在這裡,我們必須使用製造商在其數據表中提供的資訊。簡單總結一下:我們需要啟動溫度採樣通道(預設為睡眠模式)並讀取儲存在組件 ROM 中的一些校準常數,稍後我們將需要這些校準常數來計算溫度。

這篇文章的目的不是學習如何使用 BME280,因此我將跳過其使用詳細信息,您可以在其數據表中找到這些詳細信息。

初始化看起來像這樣:

#ifndef BME280_H_
#define BME280_H_

void  BME280_init(void);
float BME280_get_temperature(void);

#endif // BME280_H_
登入後複製
登入後複製
登入後複製

詳情可評論。我們讀取的校準值儲存在名為 dig_temp1、dig_temp2 和 dig_temp3 的變數中。這些變數被宣告為全域變量,因此它們可用於庫中的其餘函數。但是,它們被聲明為靜態,因此只能在庫內存取。圖書館外的任何人都不需要存取或修改這些值。

我們也看到對 I2C 指令的回傳值進行檢查,如果失敗,函數執行將停止。這很好,但還可以改進。如果是這種情況,通知 BME280_init 函數的呼叫者出現問題不是更好嗎?為此,我們在 bme280.h 檔案中定義以下枚舉。

我對它們使用 typedef。關於 typedef 的使用存在爭議,因為它們以隱藏細節為代價提高了程式碼的可讀性。這是個人喜好的問題,並確保開發團隊的所有成員都在同一頁上。

void BME280_init(void)
{
}

float BME280_get_temperature(void)
{
}
登入後複製
登入後複製

兩個注意事項:我通常在 typedef 中添加 _t 後綴以表明它們是 typedef,並且在 typedef 的值或成員中添加 typedef 前綴,在本例中為 BME280_Status_。後者是為了避免來自不同函式庫的枚舉之間的衝突。如果每個人都使用 OK 作為枚舉,我們就會遇到麻煩。

現在我們可以修改 BME280_init 函數的宣告(bme280.h)和定義(bme280.c)以傳回狀態。我們函數的最終版本將是:

void BME280_init(void)
{
    MX_I2C1_Init();
}
登入後複製
登入後複製
#include "i2c.h"
#include <stdint.h>

#define BME280_TX_BUFFER_SIZE 32U
#define BME280_RX_BUFFER_SIZE 32U
#define BME280_TIMEOUT        200U
#define BME280_ADDRESS        0x77U
#define BME280_REG_CTRL_MEAS  0xF4U
#define BME280_REG_DIG_T      0x88U

static uint16_t dig_temp1 = 0U;
static int16_t  dig_temp2 = 0;
static int16_t  dig_temp3 = 0;

void BME280_init(void)
{
    uint8_t idx                              = 0U;
    uint8_t tx_buffer[BME280_TX_BUFFER_SIZE] = {0};
    uint8_t rx_buffer[BME280_RX_BUFFER_SIZE] = {0};

    HAL_StatusTypeDef status = HAL_ERROR;

    MX_I2C1_Init();

    tx_buffer[idx++] = 0b10100011;

    status = HAL_I2C_Mem_Write(
        &hi2c1, BME280_ADDRESS << 1U, BME280_REG_CTRL_MEAS,
        1U, tx_buffer, (uint16_t)idx, BME280_TIMEOUT);

    if (status != HAL_OK)
        return;

    status = HAL_I2C_Mem_Read(
        &hi2c1, BME280_ADDRESS << 1U, BME280_REG_DIG_T, 1U,
        rx_buffer, 6U, BME280_TIMEOUT);

    if (status != HAL_OK)
        return;

    dig_temp1 = ((uint16_t)rx_buffer[0]);
    dig_temp1 =
        dig_temp1 | (((uint16_t)rx_buffer[1]) << 8U);

    dig_temp2 = ((int16_t)rx_buffer[2]);
    dig_temp2 = dig_temp2 | (((int16_t)rx_buffer[3]) << 8U);

    dig_temp3 = ((int16_t)rx_buffer[4]);
    dig_temp3 = dig_temp3 | (((int16_t)rx_buffer[5]) << 8U);

    return;
}
登入後複製

由於我們使用狀態枚舉,因此我們必須在 bme280.c 檔案中包含 bme280.h 檔案。我們已經初始化了該函式庫。現在,讓我們建立一個函數來檢索溫度。它看起來像這樣:

typedef enum
{
    BME280_Status_Ok,
    BME280_Status_Status_Err,
} BME280_Status_t;
登入後複製

你已經注意到了,對吧?我們修改了函數簽名,以便它傳回一個狀態來指示元件是否有通訊問題,並且結果透過作為參數傳遞給函數的指標傳回。如果您遵循該範例,請記住修改 bme280.h 檔案中的函數宣告以使它們相符。

BME280_Status_t BME280_init(void);
登入後複製

太棒了!此時,在應用程式中我們可以有:

#include "i2c.h"
#include <stdint.h>

int main(void)
{
    uint8_t  idx           = 0U;
    uint8_t  tx_buffer[64] = {0};
    uint8_t  rx_buffer[64] = {0};
    uint16_t dig_temp1     = 0U;
    int16_t  dig_temp2     = 0;
    int16_t  dig_temp3     = 0;

    MX_I2C1_Init();

    tx_buffer[idx++] = 0b10100011;

    HAL_I2C_Mem_Write(&hi2c1, 0x77U << 1U, 0xF4U, 1U,
                      tx_buffer, 1U, 200U);

    HAL_I2C_Mem_Read(&hi2c1, 0x77U << 1U, 0x88U, 1U,
                     rx_buffer, 6U, 200U);

    dig_temp1 = ((uint16_t)rx_buffer[0]) |
                (((uint16_t)rx_buffer[1]) << 8U);

    dig_temp2 = (int16_t)(((uint16_t)rx_buffer[2]) |
                          (((uint16_t)rx_buffer[3]) << 8U));

    dig_temp3 = (int16_t)(((uint16_t)rx_buffer[4]) |
                          (((uint16_t)rx_buffer[5]) << 8U));

    while (1)
    {
        float   temperature = 0.0f;
        int32_t adc_temp    = 0;
        int32_t t_fine      = 0;
        float   var1        = 0.0f;
        float   var2        = 0.0f;

        HAL_I2C_Mem_Read(&hi2c1, 0x77U << 1U, 0xFAU, 1U,
                         rx_buffer, 3U, 200U);

        adc_temp =
            (int32_t)((((uint32_t)rx_buffer[0]) << 12U) |
                      (((uint32_t)rx_buffer[1]) << 4U) |
                      (((uint32_t)rx_buffer[2]) >> 4U));

        var1 = (((float)adc_temp) / 16384.0f -
                ((float)dig_temp1) / 1024.0f) *
               ((float)dig_temp2);
        var2 = ((((float)adc_temp) / 131072.0f -
                 ((float)dig_temp1) / 8192.0f) *
                (((float)adc_temp) / 131072.0f -
                 ((float)dig_temp1) / 8192.0f)) *
               ((float)dig_temp3);

        t_fine = (int32_t)(var1 + var2);

        temperature = ((float)t_fine) / 5129.0f;

        // Temperature available for the application.
    }
}
登入後複製
登入後複製
登入後複製
登入後複製

超乾淨!這是可讀的。忽略 STM32CubeMX/IDE 中 Error_Handler 函數的使用。一般不建議使用它,但對我們來說,它是有效的。那麼,完成了嗎?

嗯,不!我們已將與元件的交互封裝到自己的文件中。但它的程式碼仍然在呼叫目標函數(HAL函數)!如果我們改變目標,我們就必須重寫庫!提示:我們還沒有在 bme280_interface.h 檔案中編寫任何內容。現在讓我們解決這個問題。

介面聲明

如果我們查看 bme280.c 文件,我們與目標的交互有三重:初始化週邊、寫入/發送位元組以及讀取/接收位元組。因此,我們要做的就是在 bme280_interface.h 檔案中聲明這三個交互作用。

#ifndef BME280_H_
#define BME280_H_

void  BME280_init(void);
float BME280_get_temperature(void);

#endif // BME280_H_
登入後複製
登入後複製
登入後複製

如果您注意到的話,我們也為介面狀態定義了一種新類型。現在,我們不再直接呼叫目標函數,而是從 bme280.c 檔案中呼叫這些函數。

void BME280_init(void)
{
}

float BME280_get_temperature(void)
{
}
登入後複製
登入後複製

Et voilà! 目標依賴項已從庫中消失。我們現在有了一個適用於 STM32、MSP430、PIC32 等的函式庫。在這三個庫文件中,不應出現任何特定於任何目標的內容。唯一剩下的是什麼?好了,定義介面函數。這是唯一需要針對每個目標遷移/調整的部分。

我通常在資料夾Application/bsp/components/中進行。

我們建立一個名為 bme280_implementation.c 的文件,其中包含以下內容:

void BME280_init(void)
{
    MX_I2C1_Init();
}
登入後複製
登入後複製

這樣,如果我們想在另一個專案或另一個目標上使用該程式庫,我們只需要修改 bme280_implementation.c 檔案即可。其餘部分保持完全相同。

其他需要考慮的方面

至此,我們已經看到了一個函式庫的基本範例。這種實作是最簡單、最安全、最常見的。然而,根據我們項目的特點,有不同的變體。在此範例中,我們了解如何在連結時執行實作選擇。也就是說,我們有 bme280_implementation.c 文件,它提供了編譯/連結過程中介面函數的定義。如果我們想要有兩個實作會怎樣?一個用於 I2C 通信,另一個用於 SPI 通信。在這種情況下,我們需要使用函數指標在運行時指定實作。

另一方面是,在這個例子中,我們假設系統中只有一個 BME280。如果我們有多個的話會發生什麼事?我們是否應該複製/貼上程式碼並為 BME280_1 和 BME280_2 等函數添加前綴?不,這並不理想。我們要做的是使用處理程序來允許我們在元件的不同實例上使用相同的函式庫。

這些方面以及如何在硬體可用之前測試我們的庫是另一篇文章的主題,我們將在以後的文章中介紹。目前,我們沒有理由不正確實作庫。然而,我的第一個建議(矛盾的是,我留到最後的建議)是,首先也是最重要的,確保製造商尚未為其組件提供官方庫。這是啟動和運行庫的最快方法。請放心,製造商提供的程式庫可能會遵循與我們今天看到的類似的實現,我們的工作將是使介面實現部分適應我們的目標或產品。


如果您對這個主題感興趣,您可以在我的部落格上找到這篇文章以及其他與嵌入式系統開發相關的文章! ?

以上是可重複使用元件庫:簡化目標之間的遷移的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1663
14
CakePHP 教程
1419
52
Laravel 教程
1313
25
PHP教程
1263
29
C# 教程
1236
24
C#與C:歷史,進化和未來前景 C#與C:歷史,進化和未來前景 Apr 19, 2025 am 12:07 AM

C#和C 的歷史與演變各有特色,未來前景也不同。 1.C 由BjarneStroustrup在1983年發明,旨在將面向對象編程引入C語言,其演變歷程包括多次標準化,如C 11引入auto關鍵字和lambda表達式,C 20引入概念和協程,未來將專注於性能和系統級編程。 2.C#由微軟在2000年發布,結合C 和Java的優點,其演變注重簡潔性和生產力,如C#2.0引入泛型,C#5.0引入異步編程,未來將專注於開發者的生產力和雲計算。

C和XML的未來:新興趨勢和技術 C和XML的未來:新興趨勢和技術 Apr 10, 2025 am 09:28 AM

C 和XML的未來發展趨勢分別為:1)C 將通過C 20和C 23標準引入模塊、概念和協程等新特性,提升編程效率和安全性;2)XML將繼續在數據交換和配置文件中佔據重要地位,但會面臨JSON和YAML的挑戰,並朝著更簡潔和易解析的方向發展,如XMLSchema1.1和XPath3.1的改進。

繼續使用C:耐力的原因 繼續使用C:耐力的原因 Apr 11, 2025 am 12:02 AM

C 持續使用的理由包括其高性能、廣泛應用和不斷演進的特性。 1)高效性能:通過直接操作內存和硬件,C 在系統編程和高性能計算中表現出色。 2)廣泛應用:在遊戲開發、嵌入式系統等領域大放異彩。 3)不斷演進:自1983年發布以來,C 持續增加新特性,保持其競爭力。

C多線程和並發:掌握並行編程 C多線程和並發:掌握並行編程 Apr 08, 2025 am 12:10 AM

C 多線程和並發編程的核心概念包括線程的創建與管理、同步與互斥、條件變量、線程池、異步編程、常見錯誤與調試技巧以及性能優化與最佳實踐。 1)創建線程使用std::thread類,示例展示瞭如何創建並等待線程完成。 2)同步與互斥使用std::mutex和std::lock_guard保護共享資源,避免數據競爭。 3)條件變量通過std::condition_variable實現線程間的通信和同步。 4)線程池示例展示瞭如何使用ThreadPool類並行處理任務,提高效率。 5)異步編程使用std::as

C和XML:探索關係和支持 C和XML:探索關係和支持 Apr 21, 2025 am 12:02 AM

C 通過第三方庫(如TinyXML、Pugixml、Xerces-C )與XML交互。 1)使用庫解析XML文件,將其轉換為C 可處理的數據結構。 2)生成XML時,將C 數據結構轉換為XML格式。 3)在實際應用中,XML常用於配置文件和數據交換,提升開發效率。

C#vs. C:學習曲線和開發人員的經驗 C#vs. C:學習曲線和開發人員的經驗 Apr 18, 2025 am 12:13 AM

C#和C 的学习曲线和开发者体验有显著差异。1)C#的学习曲线较平缓,适合快速开发和企业级应用。2)C 的学习曲线较陡峭,适用于高性能和低级控制的场景。

C社區:資源,支持和發展 C社區:資源,支持和發展 Apr 13, 2025 am 12:01 AM

C 學習者和開發者可以從StackOverflow、Reddit的r/cpp社區、Coursera和edX的課程、GitHub上的開源項目、專業諮詢服務以及CppCon等會議中獲得資源和支持。 1.StackOverflow提供技術問題的解答;2.Reddit的r/cpp社區分享最新資訊;3.Coursera和edX提供正式的C 課程;4.GitHub上的開源項目如LLVM和Boost提陞技能;5.專業諮詢服務如JetBrains和Perforce提供技術支持;6.CppCon等會議有助於職業

現代C設計模式:構建可擴展和可維護的軟件 現代C設計模式:構建可擴展和可維護的軟件 Apr 09, 2025 am 12:06 AM

現代C 設計模式利用C 11及以後的新特性實現,幫助構建更靈活、高效的軟件。 1)使用lambda表達式和std::function簡化觀察者模式。 2)通過移動語義和完美轉發優化性能。 3)智能指針確保類型安全和資源管理。

See all articles