溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C語言宏函數container?of()怎么使用

發布時間:2021-12-20 09:08:26 來源:億速云 閱讀:180 作者:iii 欄目:開發技術
# C語言宏函數container_of()怎么使用

## 引言

在Linux內核開發中,`container_of()`宏是一個極其重要且常用的工具。它能夠通過結構體成員的地址反向推導出整個結構體的起始地址,這種技術在鏈表、設備驅動等場景中廣泛應用。本文將深入解析`container_of()`的原理、使用方法以及實際應用案例。

---

## 一、container_of()宏概述

### 1.1 什么是container_of()

`container_of()`是Linux內核中定義的一個宏,其作用是通過結構體中某個成員的地址,計算出該結構體的起始地址。這種技術在內核數據結構(如鏈表、設備驅動模型)中被頻繁使用。

### 1.2 宏定義源碼

```c
// Linux內核中的定義(簡化版)
#define container_of(ptr, type, member) ({              \
    const typeof(((type *)0)->member) *__mptr = (ptr); \
    (type *)((char *)__mptr - offsetof(type, member)); })
  • ptr:結構體成員的指針
  • type:結構體類型
  • member:成員在結構體中的名稱

二、container_of()工作原理

2.1 關鍵機制:offsetof

offsetof(type, member)是一個標準庫宏,用于計算結構體成員相對于結構體起始地址的偏移量。例如:

struct sample {
    int a;
    char b;
    double c;
};

// 假設double在64位系統偏移量為8
size_t offset = offsetof(struct sample, c); // 可能返回8

2.2 計算步驟解析

container_of(&obj->member, struct obj, member)為例: 1. 通過typeof獲取成員的類型并做類型檢查 2. 使用offsetof計算成員偏移量 3. 將成員指針轉換為char*(確保字節級計算) 4. 減去偏移量得到結構體起始地址


三、使用場景與示例

3.1 Linux鏈表中的應用

內核鏈表list_head的典型用法:

struct task_struct {
    int pid;
    struct list_head tasks; // 嵌入的鏈表節點
};

// 通過tasks節點獲取task_struct
struct task_struct *task = container_of(ptr, struct task_struct, tasks);

3.2 實際代碼示例

#include <stdio.h>
#include <stddef.h>

#define container_of(ptr, type, member) ({              \
    const typeof(((type *)0)->member) *__mptr = (ptr);  \
    (type *)((char *)__mptr - offsetof(type, member)); })

struct student {
    int id;
    char name[20];
    float score;
};

int main() {
    struct student stu = {101, "Alice", 95.5};
    float *score_ptr = &stu.score;
    
    // 通過score成員反推student結構體
    struct student *s = container_of(score_ptr, struct student, score);
    
    printf("ID: %d, Name: %s\n", s->id, s->name);
    return 0;
}

輸出結果:

ID: 101, Name: Alice

四、常見問題與注意事項

4.1 類型安全檢查

typeof和指針強制轉換確保了類型安全。如果錯誤地傳遞了成員名,編譯時會報錯。

4.2 非GCC編譯器的兼容性

原始實現依賴GCC擴展語法({...}),在其他編譯器中可能需要改寫:

// 替代方案
#define container_of(ptr, type, member) \
    ((type *)((char *)(ptr) - offsetof(type, member)))

4.3 性能影響

container_of()在運行時只有簡單的指針運算,沒有性能開銷。


五、高級應用技巧

5.1 嵌套結構體處理

對于多層嵌套的結構體,可以鏈式調用:

struct A {
    struct B b;
};

struct B {
    int val;
};

struct B *b_ptr = &obj.a.b;
struct A *a_ptr = container_of(b_ptr, struct A, b);

5.2 結合typeof動態獲取類型

#define get_container(ptr, member) \
    container_of(ptr, typeof(*ptr), member)

六、與其他技術的對比

6.1 與C++的offsetof對比

C++中可以通過:

reinterpret_cast<T*>(reinterpret_cast<char*>(ptr) - offsetof(T, member))

實現類似功能,但缺乏編譯時類型檢查。

6.2 與面向對象設計的關聯

這種技術實現了類似”子類通過基類指針向上轉型”的效果。


七、內核實際案例

7.1 進程調度器中的使用

kernel/sched/core.c中,通過task_structse成員獲取任務指針:

struct task_struct *p = container_of(se, struct task_struct, se);

7.2 設備驅動模型

struct device嵌入到具體設備結構中時,常用此宏反向引用。


八、總結

container_of()宏展示了C語言指針操作的強大能力,其核心思想可以歸納為: 1. 通過成員地址減去偏移量得到基地址 2. 依賴編譯器的類型檢查保證安全 3. 在資源受限環境下實現高效的對象定位

掌握這個宏對于理解Linux內核和開發高性能C程序至關重要。


附錄:完整參考實現

#ifndef container_of
#define container_of(ptr, type, member) ({              \
    const typeof(((type *)0)->member) *__mptr = (ptr);  \
    (type *)((char *)__mptr - offsetof(type, member)); })
#endif

注意:實際內核代碼還包含額外的編譯器屬性檢查,本文為簡化說明進行了適當裁剪。 “`

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女