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

C 語言進階筆記(一):變數儲存類別、記憶體佈局與關鍵字深度解析

     編輯:關於C語言

C 語言進階筆記(一):變數儲存類別、記憶體佈局與關鍵字深度解析

程式設計師對話:
A:「老兄,最近手頭緊,借點錢?」
B:「成啊,要多少?」
A:「一千行不行?」
B:「咱倆誰跟誰!給你湊個整——1024,拿去花。」


前言

C 語言允許直接操作實體位址,適合核心與驅動程式開發。有句業界名言:「普通人學 C 三年不入門,五年不熟悉,十年不敢說精通。」學習關鍵在於:多寫碼、多除錯(必要時用「小黃鴨除錯法」)、多思考、遇到問題先自行深入研究解決。以下筆記整理自《C 語言深度解剖》。

一、變數定義與宣告的本質差異

  • 定義:建立物件並分配記憶體
  • 宣告:僅告知編譯器物件存在,不分配記憶體

二、命名慣例

  • 一般變數:駝峰式(CamelCase)+ 必要前後綴
  • 巨集、列舉常數、唯讀變數:全大寫 + 底線分隔單字

三、C 語言四大儲存類別

auto、extern、register、static——定義變數時只能指定其一。

四、行程記憶體空間劃分

區段內容特性
程式碼區CPU 執行的機器指令可共享、唯讀
BSS 區未初始化的全域/靜態變數程式啟動時清零
資料區已初始化的全域/靜態變數、常數資料程式載入時由映像檔初始化
堆疊區函式參數、返回值、區域變數編譯器自動管理、即時分配釋放
堆積區malloc() 分配的記憶體塊程式設計師手動管理、易發生記憶體洩漏

register 變數可能存於 CPU 暫存器,無法取址(不能用 & 運算子)。

五、static 的雙重角色

1. 修飾變數

  • 靜態全域變數:儲存於靜態區,作用域僅限定義所在檔案,他檔 extern 也不可見
  • 靜態區域變數:儲存於靜態區,作用域僅限定義所在函式,同檔其他函式也不可存取

2. 修飾函式

限制函式作用域於本檔(內部函式),避免多檔協作時發生同名衝突。

六、sizeof 關鍵字細節

int i = 0;
sizeof(int);   // 型別需加括號
sizeof i;      // 變數括號可省略
sizeof(i);     // 變數加括號也合法
sizeof int;    // ❌ 錯誤:型別不可省略括號

sizeof 僅計算型別大小,不存取記憶體,故不會觸發位址越界。

七、signed / unsigned 隱含轉換陷阱

例 1:混合算術運算

unsigned int a = 6;
int b = -20;
(a + b > 6) ? puts(">6") : puts("<=6");  // 輸出 ">6"

原因:b 隱性轉為 unsigned,-20 變成極大正數,導致 a+b 遠大於 6。

例 2:char 有號性與 strlen

char a[1000];
for (int i = 0; i < 1000; i++) a[i] = -1 - i;
printf("%d", strlen(a));  // 輸出 255(視實作而定)

原因:char 是否有號由實作定義;若為 signed char,-1-i 會在 i=255 時產生 \0,提前結束字串。

八、void 與泛型指標

  • void:空型別,用於無回傳值函式
  • void*:泛型指標,可指向任意型別資料
  • 任意型別指標可隱性轉換給 void*,無需強制轉型

九、case 標籤限制

只能是整數或字元常數/常數運算式。

十、const 唯讀變數

  • 本質仍是變數,具備唯讀屬性,不可當作編譯期常數使用(如陣列尺寸)
  • 可修飾函式參數,防止函式體內意外修改
  • 編譯器通常不為其分配記憶體,存於符號表,提升存取效率

十一、volatile:防止編譯器過度優化

int i = 10;
int j = i;  // (1)
int k = i;  // (2) 編譯器可能優化:直接用暫存器值,不重讀記憶體

加上 volatile:

volatile int i = 10;
int j = i;  // (3) 強制從記憶體讀取
int k = i;  // (4) 再次從記憶體讀取

適用場景

  • 硬體暫存器/連接埠資料
  • 多執行緒共享變數
  • 訊號處理函式存取的變數

十二、大小端模式

檢測程式

int checkSystem() {
    union { int i; char ch; } c;
    c.i = 1;
    return (c.ch == 1);  // 1=Little-endian, 0=Big-endian
}
  • 大端序:高位元組存低位址
  • 小端序:高位元組存高位址(x86 架構)

十三、結構體記憶體對齊

// 版本 1:12 位元組
struct TestStruct1 { char c1; short s; char c2; int i; };

// 版本 2:8 位元組(重新排序減少填充)
struct TestStruct2 { char c1; char c2; short s; int i; };

處理器存取對齊記憶體僅需一次總線週期,未對齊需兩次。可用 #pragma pack(n) 改變預設對齊(n=1,2,4,8,16…)。

十四、列舉型別 enum

enum Color { GREEN = 1, RED, BLUE, GREEN_RED = 10, GREEN_BLUE } ColorVal;
// 值:GREEN=1, RED=2, BLUE=3, GREEN_RED=10, GREEN_BLUE=11

十五、函式撰寫規範

最小函式標頭註解

// 功能: 改變緩衝區大小
// 參數: nNewSize 緩衝區新長度
// 返回值: 緩衝區目前長度
// 說明: 保持原資料內容不變

完整函式文檔範本

/*************************************************************************
 * Function Name : nucFindThread
 * Create Date   : 2000/01/07
 * Author        : your name/your company
 * Description   : Find a proper thread in thread array.
 * Param         : ThreadNo : ...
 * Return Code   : ERROR_Fail / ERROR_SUCCEED
 * Global Var    : DISP_wuiSegmentAppID
 * Revision History
 * V0.5 2008/01/07 your name ...
 ************************************************************************/

編碼細節建議

  • 防禦性程式設計
  • 縮排統一 4 空格
  • 變數定義與執行語句間空一行
  • 邏輯相關語句不空行,其餘空行分隔
  • 複雜函式在分支/迴圈結束處加註解 // end "for(...)"
  • 入口斷言 assert(NULL != p);
  • 遞迴深度過大恐導致堆疊溢位
  • 嚴禁返回指向堆疊記憶體的指標(函式結束時自動銷毀)

十六、檔案命名與標頭檔架構

  • 命名:模組縮寫 + 小寫名稱
  • 標頭檔包含:版權、模組、CPU/RTOS、建立日期、作者、摘要、修訂歷史、防重複包含巨集、除錯開關、引入檔、巨集定義、結構定義、原型宣告、全域變數宣告、檔案靜態變數、函式定義

十七、後續學習計畫

  • 研讀《C Primer Plus》(第 2 版)前置處理器章節
  • 學習 ARM 組合語言
  • 從組語層面理解 C:姚新顏《C 語言:標準與實作》《C/C++ 深層探索》(x86 組語)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved