- 浏览: 128811 次
- 性别:
- 来自: 北京
-
最新评论
-
yangtaoxf126.com:
public class SimpleJDBC {
publ ...
oracle的sys用户怎么通过jdbc连接
在学习Linux驱动的过程中,遇到一个宏叫做container_of。
该宏定义在include/linux/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) );})
它的作用显而易见,那就是根据一个结构体变量中的一个域成员变量的指针来获取指向 整个结构体变量的指针。比如,有一个结构体变量,其定义如下:
struct demo_struct {
type1 member1;
type2 member2;
type3 member3;
type4 member4;
};
struct demo_struct demo;
同时,在另一个地方,获得了变量demo中的某一个域成员变量的指针,比如:
type3 *memp = get_member_pointer_from_somewhere();
此时,如果需要获取指向整个结构体变 量的指针,而不仅仅只是其某一个域成员变量的指针,我们就可以这么做:
struct demo_struct *demop = container_of(memp, struct demo_struct, member3);
这样,我们就通过一个结构体变量的一个域成 员变量的指针获得了整个结构体变量的指针。
下面说一说我对于这个container_of的实现的理解:
首先,我们将 container_of(memp, struct demo_struct, type3)根据宏的定义进行展开如下:
struct demo_struct *demop = ({ \
const typeof( ((struct demo_struct *)0)->member3 ) *__mptr = (memp); \
(struct demo_struct *)( (char *)__mptr - offsetof(struct demo_struct, member3) );})
其中,typeof是GNU C对标准C的扩展,它的作用是根据变量获取变量的类型。因此,上述代码中的第2行的作用是首先使用typeof获取结构体域变量member3的类型为 type3,然后定义了一个type3指针类型的临时变量__mptr,并将实际结构体变量中的域变量的指针memp的值赋给临时变量__mptr。
(char *)__mptr转换为字节型指针。(char *)__mptr - offsetof(type,member) )用来求出结构体起始地址(为char *型指针),然后(type *)( (char *)__mptr - offsetof(type,member) )在(type *)作用下进行将字节型的结构体起始指针转换为type *型的结构体起始指针。
假 设结构体变量demo在实际内存中的位置如下图所示:
demo
+-------------+ 0xA000
| member1 |
+-------------+ 0xA004
| member2 |
+-------------+ 0xA010
| member3 |
+-------------+ 0xA018
| member4 |
+-------------+
则,在执行了上述代码的第2行之后__mptr的值即为0xA010。
再看上述代 码的第3行,其中需要说明的是offsetof,它定义在include/linux/stddef.h中,其定义如下:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
先分析一下这个 宏的运行机理:
一共4步
1. ( (TYPE *)0 ) 将零转型为TYPE类型指针;
2. ((TYPE *)0)->MEMBER 访问结构中的数据成员;
3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址;
4.(size_t)(&(((TYPE*)0)->MEMBER))结果转换类型。巧妙之处在于将0转 换成(TYPE*),结构以内存空间首地址0作为起始地址,则成员地址自然为偏移地址;
同样,我们将上述的offsetof调用展开,即为:
(struct demo_struct *)( (char *)__mptr - ((size_t) &((struct demo_struct *)0)->member3) );
可见,offsetof的实现原理如上所述,就是取结构体中的域成员相对于地址0的偏移地址,也就是域 成员变量相对于结构体变量首地址的偏移。
因此,offsetof(struct demo_struct, member3)调用返回的值就是member3相对于demo变量的偏移。结合上述给出的变量地址分布图可知,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,也就是结构体变量demo的首地址(如上图所示)。
这就是从结构体某成员变量指针来求出 该结构体的首指针。指针类型从结构体某成员变量类型转换为该结构体类型。
由此,container_of实现了根据一个结构体变量中的一个域成员 变量的指针来获取指向整个结构体变量的指针的功能。
以上内容载自网络,这篇文章分析的很透彻,顺便说一下,宋宝华的《linux设备驱动 开发详解》P132 最后一行当中对该宏的参数解释是错误的!当然了,暇不掩瑜!
以下是我自己的一些理解:
首先,我定义了一个字符设备结 构体
struct globalmem_dev
{
struct cdev my_cdev; //字符设备之基础结构体
unsigned char mem[GLOBALMEM_SIZE];
struct semaphore sem;/
};
接下来我实例化了一个该设备的指针对象
struct globalmem_dev *pdev;
后来在open函数中我是这么来用的
int globalmem_open(struct inode *inode, struct file *filp)关于filp的产生和消亡参见《驱动详解》P92
{
struct globalmem_dev *pdev;
printk("\nFunction globalmem_open Invoked\n");
pdev = container_of(inode->i_cdev, struct globalmem_dev, my_cdev);
filp->private_da
ta = pdev;
if(down_trylock(&pdev->sem))//获得信号量, 真的我爱 container_of!!!! 我爱死container_of 了!!!
return -EBUSY;
return 0;
}
对 以上用法的说明:
参数3是参数2这个结构体的一个成员的名字!而不是类型名!参数1是一个指针,它指向参数3这个成员
inode中的i_cdev字段是一个指针,当我们成功insmod了一个设备驱动的时候,我们会通过mknod创建一个设备文件节点并和具体设备 (驱动)想关联,这个设备文件节点所对应的就是struct inode结构体的一个实例,这个结构体有一个字段i_cdev,是个struct cdev类型的指针,它会指向设备结构体的my_cdev字段。至此你已经有了一个指向某个 globalmem_dev的my_cdev字段的一个指针(在调用open前pdev的内存分配假定已经完成)由此container_of可以帮你计 算出指向该设备结构体的指针。
当一个设备驱动对应多个设备(子设备)时,你就知道container_of发挥的作用了!当你针对每一个设备调用open时,因为每个设备对应的设备文 件节点不一样,那么根据该节点的i_cdev字段所计算的设备结构体指针也不一样,你就可以找到特定节点所对应的设备结构体!而不至于对不同的子设备编写 大同小异的各自的设备驱动。
该宏定义在include/linux/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) );})
它的作用显而易见,那就是根据一个结构体变量中的一个域成员变量的指针来获取指向 整个结构体变量的指针。比如,有一个结构体变量,其定义如下:
struct demo_struct {
type1 member1;
type2 member2;
type3 member3;
type4 member4;
};
struct demo_struct demo;
同时,在另一个地方,获得了变量demo中的某一个域成员变量的指针,比如:
type3 *memp = get_member_pointer_from_somewhere();
此时,如果需要获取指向整个结构体变 量的指针,而不仅仅只是其某一个域成员变量的指针,我们就可以这么做:
struct demo_struct *demop = container_of(memp, struct demo_struct, member3);
这样,我们就通过一个结构体变量的一个域成 员变量的指针获得了整个结构体变量的指针。
下面说一说我对于这个container_of的实现的理解:
首先,我们将 container_of(memp, struct demo_struct, type3)根据宏的定义进行展开如下:
struct demo_struct *demop = ({ \
const typeof( ((struct demo_struct *)0)->member3 ) *__mptr = (memp); \
(struct demo_struct *)( (char *)__mptr - offsetof(struct demo_struct, member3) );})
其中,typeof是GNU C对标准C的扩展,它的作用是根据变量获取变量的类型。因此,上述代码中的第2行的作用是首先使用typeof获取结构体域变量member3的类型为 type3,然后定义了一个type3指针类型的临时变量__mptr,并将实际结构体变量中的域变量的指针memp的值赋给临时变量__mptr。
(char *)__mptr转换为字节型指针。(char *)__mptr - offsetof(type,member) )用来求出结构体起始地址(为char *型指针),然后(type *)( (char *)__mptr - offsetof(type,member) )在(type *)作用下进行将字节型的结构体起始指针转换为type *型的结构体起始指针。
假 设结构体变量demo在实际内存中的位置如下图所示:
demo
+-------------+ 0xA000
| member1 |
+-------------+ 0xA004
| member2 |
+-------------+ 0xA010
| member3 |
+-------------+ 0xA018
| member4 |
+-------------+
则,在执行了上述代码的第2行之后__mptr的值即为0xA010。
再看上述代 码的第3行,其中需要说明的是offsetof,它定义在include/linux/stddef.h中,其定义如下:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
先分析一下这个 宏的运行机理:
一共4步
1. ( (TYPE *)0 ) 将零转型为TYPE类型指针;
2. ((TYPE *)0)->MEMBER 访问结构中的数据成员;
3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址;
4.(size_t)(&(((TYPE*)0)->MEMBER))结果转换类型。巧妙之处在于将0转 换成(TYPE*),结构以内存空间首地址0作为起始地址,则成员地址自然为偏移地址;
同样,我们将上述的offsetof调用展开,即为:
(struct demo_struct *)( (char *)__mptr - ((size_t) &((struct demo_struct *)0)->member3) );
可见,offsetof的实现原理如上所述,就是取结构体中的域成员相对于地址0的偏移地址,也就是域 成员变量相对于结构体变量首地址的偏移。
因此,offsetof(struct demo_struct, member3)调用返回的值就是member3相对于demo变量的偏移。结合上述给出的变量地址分布图可知,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,也就是结构体变量demo的首地址(如上图所示)。
这就是从结构体某成员变量指针来求出 该结构体的首指针。指针类型从结构体某成员变量类型转换为该结构体类型。
由此,container_of实现了根据一个结构体变量中的一个域成员 变量的指针来获取指向整个结构体变量的指针的功能。
以上内容载自网络,这篇文章分析的很透彻,顺便说一下,宋宝华的《linux设备驱动 开发详解》P132 最后一行当中对该宏的参数解释是错误的!当然了,暇不掩瑜!
以下是我自己的一些理解:
首先,我定义了一个字符设备结 构体
struct globalmem_dev
{
struct cdev my_cdev; //字符设备之基础结构体
unsigned char mem[GLOBALMEM_SIZE];
struct semaphore sem;/
};
接下来我实例化了一个该设备的指针对象
struct globalmem_dev *pdev;
后来在open函数中我是这么来用的
int globalmem_open(struct inode *inode, struct file *filp)关于filp的产生和消亡参见《驱动详解》P92
{
struct globalmem_dev *pdev;
printk("\nFunction globalmem_open Invoked\n");
pdev = container_of(inode->i_cdev, struct globalmem_dev, my_cdev);
filp->private_da
ta = pdev;
if(down_trylock(&pdev->sem))//获得信号量, 真的我爱 container_of!!!! 我爱死container_of 了!!!
return -EBUSY;
return 0;
}
对 以上用法的说明:
参数3是参数2这个结构体的一个成员的名字!而不是类型名!参数1是一个指针,它指向参数3这个成员
inode中的i_cdev字段是一个指针,当我们成功insmod了一个设备驱动的时候,我们会通过mknod创建一个设备文件节点并和具体设备 (驱动)想关联,这个设备文件节点所对应的就是struct inode结构体的一个实例,这个结构体有一个字段i_cdev,是个struct cdev类型的指针,它会指向设备结构体的my_cdev字段。至此你已经有了一个指向某个 globalmem_dev的my_cdev字段的一个指针(在调用open前pdev的内存分配假定已经完成)由此container_of可以帮你计 算出指向该设备结构体的指针。
当一个设备驱动对应多个设备(子设备)时,你就知道container_of发挥的作用了!当你针对每一个设备调用open时,因为每个设备对应的设备文 件节点不一样,那么根据该节点的i_cdev字段所计算的设备结构体指针也不一样,你就可以找到特定节点所对应的设备结构体!而不至于对不同的子设备编写 大同小异的各自的设备驱动。
发表评论
-
__define_initcall 作用
2010-11-25 19:26 1258前言 宏定义__define_initcall ... -
转载--Linux 2.6内核I/O端口资源管理
2010-11-02 15:39 855申明:本文章是对“Linux对I/O端口资源的管理”该文章进行 ... -
linux 2.6线程创建源码分析
2010-11-02 15:09 1134上章讲到线程,现在对线程创建的代码流程分析下。来一步一步揭开她 ... -
linux 2.6进程与线程
2010-11-02 15:09 12431 > 线程和进程的 ... -
linux中ELF加载过程分析
2010-10-19 11:16 1960linux中ELF加载过程分析 - 博青港湾-技术空间 - ... -
Linux设备模型 学习总结
2010-10-13 21:21 961看LDD3中设备模型一章,觉得思维有些混乱。这里从整体的角度来 ... -
linux软中断的实现
2010-10-13 21:12 1121中断服务程序往往都是在CPU关中断的条件下执行的,以避免中断 ... -
zImage / vmlinux / Image生成的流程图
2010-10-13 21:11 2449SRC_TREE :=./ HEADER_PATH ... -
执行程序时内存管理的情景
2010-10-13 21:07 1471do_execve ->open_exec->de ... -
Linux Kernel 2.6进程调度的分析(揭示了几乎所有2.6调度的东西)
2010-10-13 20:16 1921第一章 Kernel 2.4存在的 ... -
ibm developer blog
2010-10-10 10:05 888Linux slab 分配器剖析 http://www.ibm ... -
linux2.6.29 启动过程详细分析
2010-08-12 16:02 1374突然心血来潮,想自己写个模块,于是就把linux2.6.29的 ... -
Linux内存:内存管理的实质
2010-08-04 21:22 711<转 http://linux.chinaunix. ... -
高级IO操作——ioctl
2010-07-23 20:48 1464_IO, _IOR, _IOW, _IOWR 宏的用法与解析 ... -
主设备号、次设备号
2010-07-23 16:13 933主设备号、次设备号分 ... -
Linux在控制台下不同类型文件显示不同颜色
2010-07-20 23:47 2581# ~/.bashrc: executed by bash(1 ... -
linux 编译内核 选项出错 综合
2010-07-20 23:24 1015具体错误提示见最后面 ... -
ARM SDT下汇编到GNU汇编的转换
2010-07-16 08:52 897将ARM SDT下的汇编码移植到GCC for ARM编译器时 ... -
GNU ARM 汇编指令(转)
2010-07-16 08:50 1675第一部分 Linux下ARM汇编语法尽管在Linux下使用C或 ... -
arm 嵌入式LINUX启动过程
2010-07-11 00:44 3913一位大师级的人物写的,不看要后悔的哟!! ...
相关推荐
Linux内核宏`container_of`是Linux内核中一个非常重要的工具,用于在内核代码中根据结构体的成员地址反向查找整个结构体的地址。这个宏在编写内核驱动程序时尤其常见,因为它允许程序员高效地访问与某个特定成员相...
**标题解析:** "An_IOC_Container_in_15_min" 这个标题表明了内容将介绍如何在15分钟内快速理解并构建一个IoC(Inversion of Control)容器。IoC容器是面向对象编程中一种重要的设计模式,它帮助解耦代码,提高软件...
`container_of`宏的实现基于这样的前提:如果结构体的地址与结构体内第一个成员的地址相同,则可以通过成员的地址减去它在结构体中的偏移量来得到结构体的地址。 例如,要遍历一个链表,可以使用类似以下的代码: ...
例如,如果有一个结构体`struct foo`,其中包含一个成员`bar`,`container_of(ptr, struct foo, bar)`会返回`ptr`所指向的`bar`成员所属的`struct foo`实例的地址。 在ecryptfs的初始化过程中,`ecryptfs_...
Unity Ioc(Inversion of Control)Container 是微软的开源轻量级依赖注入框架,它主要用于构建松耦合、可测试的软件系统。在Unity中,Ioc容器是关键组件,负责管理和实例化对象,同时也处理对象之间的依赖关系。让...
IOC(Inversion of Control)即控制反转,是软件设计模式中的一种,它将对象的创建和管理权交给了外部容器,而不是由对象自身来负责。这样可以降低代码之间的耦合度,提高系统的可扩展性和可维护性。在Java世界里,...
在Laravel中,依赖注入通过IOC(Inversion of Control)容器实现。这个容器负责管理并实例化应用中的所有对象,确保它们的依赖关系得到正确解决。 **Laravel IOC容器** Laravel的IOC容器是框架的心脏,它管理着...
Message listener container 需要绑定连接工厂(connection factory)、JMS Destination、JNDI Destination 解析器和 message listener bean。这四个部分结合使用,实现异步消息监听。 Spring 提供了两种 message ...
1. **IoC(Inversion of Control,控制反转)与DI(Dependency Injection,依赖注入)**:这是Spring的核心特性,它通过反转对象的创建和管理权,使得开发者不再需要在代码中硬编码依赖关系,而是通过配置文件或注解...
So, I've written a very simple JSONObject class, which can be generically used to encode/decode data into a simple container. This page assumes that you know what JSON is, and how it works.
以下是对该主题的详细知识解析: 1. GTK+概述: GTK+(GIMP Toolkit)最初是为图像处理软件GIMP设计的,随着时间的发展,它已经演变成一个强大的、可扩展的GUI构建框架,支持多种编程语言,如C、C++、Python、Java...
Spring技术内幕:深入解析Spring架构与设计原理 Spring技术内幕 Spring是一个基于Java的开源框架,旨在简化Java企业应用的开发。Spring的目标是提供一个简洁、灵活、可扩展的框架,以帮助开发者快速构建企业级...
在本文中,我们将深入探讨依赖注入的概念,并以Swift语言为例,展示如何在实际项目中实现IoC(Inversion of Control)容器。 首先,理解依赖注入的关键在于理解"依赖"。在软件工程中,一个类或函数通常需要调用其他...
- 解析:这里定义了一个名为`tzfst`的表,并通过`LIKE TABLE OF`指定了该表的数据结构(与`zfst`相同),然后通过`INSERT`语句向表中插入数据。 - **清空表** - 示例代码: ```abap DATA tzfst TYPE TABLE zfst...
throw std::out_of_range("Queue is empty") : container.front(); } bool empty() const { return container.empty(); } private: std::deque<T> container; // 使用deque作为底层容器,支持快速的前后插入和...
- 解析:此处house作为先行词,由in front of which引导定语从句,在从句中作地点状语,指房子前面有花园的位置。 16. **Miss Green took up the story at the point _______ the thief had just made off with ...
**题目5**:“Container-grown plants can be planted at any time of the year, but ______ in winter.” - **正确答案**:D. preferably - **解析**:本题考查副词的使用。“preferably”意为“最好地”,符合句意...
【高考英语易错题解析】 1. 这道题考查的是时态的运用。在第一题中,句子涉及两个时间点:before I joined them 和 now。"before I joined them" 提示了过去的一个持续动作,因此第一个空应该使用过去完成进行时,...
例子:安装: npm install --save container-ioc基本: 下面的代码示例用Typescript编写。 查看以获取使用Javascript编写的示例。步骤1.定义您的接口和类型。 类型的可能值: Symbol , string , Object 。