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

Linux 內核 container_of 宏原理深度解析:從結構體成員地址反推結構體首地址

     編輯:關於C語言

問題場景

已知結構體 struct Fox { int a, b; struct list_head list; } 中 list 成員的地址,如何獲取包含它的 Fox 結構體首地址?

核心原理:偏移量計算

  1. 將地址 0 強轉為結構體指針:(struct Fox*)0
  2. 取目標成員地址:&((struct Fox*)0)->list,即為成員在結構體中的字節偏移量。
  3. 已知成員實際地址 ptr,減去偏移量即得結構體首地址:(char*)ptr - offset。

標準宏定義(Linux kernel)

#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE*)0)->MEMBER)

#define container_of(ptr, type, member) ({ \
    const typeof(((type*)0)->member) *__mptr = (ptr); \
    (type*)((char*)__mptr - offsetof(type, member)); })
  • typeof:GCC 擴展,獲取表達式類型,保證類型安全。
  • ({ ... }):GCC 語句表達式,允許宏內多語句並返回值。
  • const typeof(...) *__mptr:防止誤修改,編譯器類型檢查。

完整演示代碼

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

struct Fox { int tail_color; int tail_length; struct list_head list; };

int main() {
    struct Fox red = {45, 10};
    printf("Fox addr: %p\n", &red);
    printf("list  addr: %p\n", &red.list);

    size_t off = offsetof(struct Fox, list);
    printf("offset: %zu\n", off);

    struct Fox *p = container_of(&red.list, struct Fox, list);
    printf("recovered: %p, color=%d, len=%d\n", p, p->tail_color, p->tail_length);
    return 0;
}

實際應用:內核鏈表遍歷

struct list_head *pos;
list_for_each(pos, &head) {
    struct Fox *fox = container_of(pos, struct Fox, list);
    // 直接訪問 fox->tail_color 等業務字段
}

優勢:業務結構體無需內嵌 prev/next 指針,僅嵌入 list_head,內核提供通用鏈表操作 API,實現數據結構與算法解耦。

避坑提示

  • 成員必須是直接嵌入,非指針嵌入。
  • 結構體不能有虛函數/虛繼承(C 無此問題)。
  • 嚴格遵循 container_of(ptr, type, member) 參數順序。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved