首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

嵌入式 C 語言編程精華:流水線優化、位操作、指針陷阱與結構體對齊實戰總結

     編輯:關於C語言

一、流水線與跳轉指令:效能的隱形殺手

嵌入式處理器(如 ARM7/9)採用流水線架構。流水線滿載時每週期完成一條指令。跳轉指令(分支、函數呼叫、循環)會清空流水線,需數週期重新填充。

對策:盡量使用條件執行指令(ARM 的 cond 後綴)替代分支跳轉,保持流水線流暢。

二、延遲循環的經驗校準

LPC2200 系列(約 60MHz)參考延遲 10ms 代碼:


for (i = 0; i < 200; ++i)
    for (j = 0; j < 200; ++j); // 空循環

注意:編譯器優化等級(-O1/-O2)可能優化掉空循環,實務應用必須用硬體定時器或內建延遲函數,不可依賴軟體循環。

三、16 位變量拆分為兩個 8 位變量

網路協議、串口傳輸常需將 16 位值拆高低位元組:


uint16_t crc = 0xABCD;
uint8_t high = (crc & 0xFF00) >> 8; // 0xAB
uint8_t low  = crc & 0x00FF;        // 0xCD

位運算 &、|、>>、<< 是嵌入式開發的基本功。

四、陣列初始化與邊界風險


int a[] = {1,2,3,4,5}; // 長度自動推導為 5
// a[5] 訪問越界 → 未定義行為(隨機值)

不指定長度便利但危險:嚴禁訪問初始化元素以外的索引。

五、ADS 編譯器不支援 printf:串口重定向調試法

ARM ADS 編譯器預設無半主機模式支援 printf。解決方案:

  1. 實作 fputc 向 UART 發送字元
  2. 或重寫 __sys_write 系統調用
  3. Keil MDK 可勾選 "Use MicroLIB" 並實作 fputc

六、位運算實用模式

操作代碼說明
置位reg |= (1 << n);將第 n 位設 1,其它不變
清零reg &= ~(1 << n);將第 n 位清 0
翻轉reg ^= (1 << n);第 n 位取反
讀取(reg >> n) & 1獲取第 n 位值
批次置位PINSEL0 |= 0x00000005;同時置位 0 和 2

七、函數指針:本質與進階用法

本質:函數名 = 函數代碼首地址。呼叫函數 = CALL address + 參數傳遞 + 返回地址入棧。核心是將地址載入 PC 暫存器。


// 定義:返回 int、接受無參數的函數指針
int (*p)(); // 括號不可省:p 先與 * 結合成指針,再與 () 結合成函數

// 對比:返回 int* 的函數
int *func(); // func 是函數名,返回 int*

進階:可「呼叫不存在的函數實體」(如跳轉到 Bootloader 地址、中斷向量表動態修改),極具靈活性也極度危險。

八、陣列指標 vs 指標陣列:一字之差,天壤之別


int (*p)[4]; // p 是指向「含 4 個 int 的陣列」的指標(行指標)
int *p[4];   // p 是「含 4 個 int* 的陣列」(指標陣列)

記憶口訣:從右往左找第一個括號。括號裡是參數 → 函數;括號裡是數字 → 陣列指標;無括號 → 指標陣列。

九、結構體傳參:值傳遞 vs 指標傳遞

  • 值傳遞:整個結構體壓棧拷貝。大結構體開銷巨大(時間+空間)。
  • 指標傳遞:僅傳 4/8 字節地址。嵌入式鐵律:大結構體必須傳指標。

十、共用體:省記憶體的雙刃劍


union Data {
    int i;
    char c;
    double d;
}; // 大小 = max(sizeof(int), sizeof(char), sizeof(double)) = 8 字節(對齊後)
  • 同一記憶體區域,同一時刻只能存一個成員。
  • 最後寫入的成員生效,讀取其他成員為未定義行為(但常用於型別雙關)。
  • 對齊規則:按最大基本型別對齊(Linux GCC 預設開啟,Turbo C 不對齊)。

十一、CPU 字長與記憶體位寬不匹配:共用體無縫轉換

8 位 MCU 發送 16 位資料:


union {
    uint16_t word;
    uint8_t byte[2];
} send_buff;

send_buff.byte[0] = low_byte;
send_buff.byte[1] = high_byte;
UART_Send(send_buff.word); // 一次發送 16 位

十二、複合賦值運算子優先級陷阱


a += 3 * 5; // 等價 a = a + (3 * 5),而非 (a + 3) * 5

+= 等複合賦值優先級低於算術運算子,右側完整表達式先求值。

總結

嵌入式 C 開發是與硬體共舞:理解流水線、精通位運算、敬畏指標、善用共用體、謹慎對齊、驯服編譯器。這 12 條精華,是從「能跑」到「穩、快、省」的進階階梯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved