亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 941 | 回復(fù): 0
打印 上一主題 下一主題

(轉(zhuǎn))container_of 理解 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2010-01-16 17:58 |只看該作者 |倒序?yàn)g覽
問題:如何通過結(jié)構(gòu)中的某個變量獲取結(jié)構(gòu)本身的指針???
關(guān)于container_of見kernel.h中:
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr:     the pointer to the member.
* @type:     the type of the container struct this is embedded in.
* @member:     the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({             \
         const typeof( ((type *)0)->member ) *__mptr = (ptr);     \
         (type *)( (char *)__mptr - offsetof(type,member) );})
container_of在Linux Kernel中的應(yīng)用非常廣泛,它用于獲得某結(jié)構(gòu)中某成員的入口地址.
關(guān)于offsetof見stddef.h中:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
TYPE是某struct的類型 0是一個假想TYPE類型struct,MEMBER是該struct中的一個成員. 由于該struct的基地址為0, MEMBER的地址就是該成員相對與struct頭地址的偏移量.
關(guān)于typeof,這是gcc的C語言擴(kuò)展保留字,用于聲明變量類型.
const typeof( ((type *)0->member ) *__mptr = (ptr);意思是聲明一個與member同一個類型的指針常量 *__mptr,并初始化為ptr.
(type *)( (char *)__mptr - offsetof(type,member) );意思是__mptr的地址減去member在該struct中的偏移量得到的地址, 再轉(zhuǎn)換成type型指針. 該指針就是member的入口地址了.
例一;
container_of宏定義在[include/linux/kernel.h]中:
#define container_of(ptr, type, member)     \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );
offsetof宏定義在[include/linux/stddef.h]中:
#define offsetof(type, member) ((size_t) &((type *)0)->member)
下面用一個測試程序test.c來說明
#include
struct student{
    char name[20];  
    char sex;
}stu={"zhangsan",'m'};
main()
{
    struct student *stu_ptr;    //存儲container_of宏的返回值
    int offset;            //存儲offsetof宏的返回值
//下面三行代碼等同于 container_of(&stu.sex,struct student, sex )參數(shù)帶入的情形
    const typeof(((struct student*)0)->sex) *_mptr = &stu.sex;
//首先定義一個 _mptr指針, 類型為struct student結(jié)構(gòu)體中sex成員的類型
//typeof 為獲。ǎǎ╯truct student*)0)->sex)的類型,此處此類型為char
//((struct student*)0)在offsetof處講解
    offset = (int)(&((struct student *)0)->sex);
/*((struct student*)0)為 把 0地址 強(qiáng)制轉(zhuǎn)化為指向student結(jié)構(gòu)體類型的指針
該指針從地址 0 開始的 21個字節(jié)用來存放name 與 sex(char name〔20〕與 char sex共21字節(jié))
sex存放在第20個字節(jié)出(從0字節(jié)開始)
&((struct student *)0)->sex 取出sex地址(此處即為20) 并強(qiáng)制轉(zhuǎn)化為整形
所以offset為20,后面的printf結(jié)果將證明這一點(diǎn)*/
    stu_ptr = (struct student *)((char*)_mptr - offset);
/*((char*)_mptr - offset)此處先把_mptr指針轉(zhuǎn)化為字符形指針
(為什么這么做呢? 如果_mptr為整形指針 _mptr - offset 相當(dāng)于減去 sizeof(int)*offset個字節(jié))
減去 offset值 相當(dāng)于 得到_mptr所在結(jié)構(gòu)體的首地址(即stu的地址)
然后我們把 該地址 強(qiáng)制轉(zhuǎn)化為 struct student類型即可正常使用了*/
    printf("offsetof stu.sex = %d\n",offset);  
    printf("stu_ptr->name:%s\tstu_ptr->sex:%c\n", stu_ptr->name, stu_ptr->sex);
    return 0;
}
例二:
它的作用顯而易見,那就是根據(jù)一個結(jié)構(gòu)體變量中的一個域成員變量的指針來獲取指向整個結(jié)構(gòu)體變量的指針。比如,有一個結(jié)構(gòu)體變量,其定義如下:
   1. struct demo_struct {
   2.     type1 member1;
   3.     type2 member2;
   4.     type3 member3;
   5.     type4 member4;
   6. };
   7.
   8. struct demo_struct demo;
同時,在另一個地方,獲得了變量demo中的某一個域成員變量的指針,比如:
   1. type3 *memp = get_member_pointer_from_somewhere();
此時,如果需要獲取指向整個結(jié)構(gòu)體變量的指針,而不僅僅只是其某一個域成員變量的指針,我們就可以這么做:
   1. struct demo_struct *demop = container_of(memp, struct demo_struct, member3);
首先,我們將container_of(memp, struct demo_struct, type3)根據(jù)宏的定義進(jìn)行展開如下:
   1. struct demo_struct *demop = ({                      \
   2.     const typeof( ((struct demo_struct *)0)->member3 ) *__mptr = (memp);    \
   3.     (struct demo_struct *)( (char *)__mptr - offsetof(struct demo_struct, member3) );})
其中,typeof是GNU C對標(biāo)準(zhǔn)C的擴(kuò)展,它的作用是根據(jù)變量獲取變量的類型。因此,上述代碼中的第2行的作用是首先使用typeof獲取結(jié)構(gòu)體域變量member3的類型為 type3,然后定義了一個type3指針類型的臨時變量__mptr,并將實(shí)際結(jié)構(gòu)體變量中的域變量的指針memp的值賦給臨時變量__mptr。
假設(shè)結(jié)構(gòu)體變量demo在實(shí)際內(nèi)存中的位置如下圖所示:
     demo
+-------------+ 0xA000
|   member1              |
+-------------+ 0xA004
|   member2             |
|                                |
+-------------+ 0xA010
|   member3             |
|                                |
+-------------+ 0xA018
|   member4             |
+-------------+
則,在執(zhí)行了上述代碼的第2行之后__mptr的值即為0xA010。
再看上述代碼的第3行,其中需要說明的是offsetof,它定義在include/linux/stddef.h中,其定義如下:
   1. 24#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
同樣,我們將上述的offsetof調(diào)用展開,即為:
   1. (struct demo_struct *)( (char *)__mptr - ((size_t) &((struct demo_struct *)0)->member3) );
可見,offsetof的實(shí)現(xiàn)原理就是取結(jié)構(gòu)體中的域成員相對于地址0的偏移地址,也就是域成員變量相對于結(jié)構(gòu)體變量首地址的偏移。
因此,offsetof(struct demo_struct, member3)調(diào)用返回的值就是member3相對于demo變量的偏移。結(jié)合上述給出的變量地址分布圖可知,offsetof(struct demo_struct, member3)將返回0x10。
于是,由上述分析可知,此時,__mptr==0xA010,offsetof(struct demo_struct, member3)==0x10。
因此, (char *)__mptr - ((size_t) &((struct demo_struct *)0)->member3) == 0xA010 - 0x10 == 0xA000,也就是結(jié)構(gòu)體變量demo的首地址(如上圖所示)。
由此,container_of實(shí)現(xiàn)了根據(jù)一個結(jié)構(gòu)體變量中的一個域成員變量的指針來獲取指向整個結(jié)構(gòu)體變量的指針的功能。

轉(zhuǎn)載于:
http://blog.csdn.net/yinkaizhong/archive/2009/04/20/4093795.aspx


本文來自ChinaUnix博客,如果查看原文請點(diǎn):http://blog.chinaunix.net/u3/105293/showart_2150888.html
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP