这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 嵌入式开发» 软件与操作系统» 【已解决】问题,关于邮箱发送消息和接收消息函数中使用的空类型指针void*

共8条 1/1 1 跳转至

【已解决】问题,关于邮箱发送消息和接收消息函数中使用的空类型指针void*

高工
2013-06-25 20:38:09 打赏

PS:VOID指针确实比较难以理解。。。。

问题,关于邮箱发送消息和接收消息函数中使用的空类型指针void*

两个函数的定义是这样的:

ERercd= tk_snd_mbx(IDmbxid,T_MSG*pk_msg);

ERercd= tk_rcv_mbx(IDmbxid,T_MSG**ppk_msg,TMOtmout);

其中T_MSG的定义如下:

typedef struct t_msg {

VPmsgque[1];/* Area for message queue */

} T_MSG;

其中VP就是typedef void *VP;

也就是说,T_MSG这个结构本身包含了一个空类型的指针

下面是我对这里使用空类型指针的理解,求鉴定。

先明确的地方:消息传递中,传递的只是地址

1tk_snd_mbx使用T_MSG*

T_MSG*是指向消息结构的指针,与msgque是相同的。这个指针是一个void*类型的指针。可以指向任意类型的数据。

所以tk_snd_mbx(IDmbxid,T_MSG*pk_msg);

这种用法,就是要向函数传递一个空类型的指针。

2tk_rcv_mbx中的使用。

这里是一个指向指针的指针(T_MSG** ppk_msg)。关于ppk_msg内核规范中有这么个说明:ppk_msg是包含消息的数据包(包括消息头在内)的起始地址。

也就是说ppk_msg是一个地址(地址1)。* ppk_msg是就是地址中的数据,这个数据也是个地址(地址2)。于是T_MSG** ppk_msg就是地址2中存储的数据。这个数据是T_MSG类型的。(不知对错,求鉴定)

在示例工程中,有这么个用法:

tk_rcv_mbx(MbxID_S,(T_MSG**)&pk_rcvmsg,-1);

其中pk_rcvmsg的定义是这样的:U_MSG *pk_rcvmsg;也是个指针。

那么&pk_rcvmsg,就是取这个指针的地址。(T_MSG**)&pk_rcvmsg就成了将地址pk_rcvmsg中存储的地址所指向的数据块,强制转换成T_MSG*类型。

刚好与函数定义部分相同。




关键词: 解决 问题 关于 邮箱 发送 消息 接收 函数

高工
2013-06-25 20:41:49 打赏
2楼

关于void型指针,我参考的这里:

http://bbs.chinaunix.net/thread-225624-1-1.html

基本上能搞明白。但是,现在的这种用法却搞不明白了。

自己这么分析,不知道对错。求鉴定


菜鸟
2013-06-25 21:12:01 打赏
3楼
http://www.tecoss.org/viewthread.php?tid=4180&extra=page%3D1

菜鸟
2013-06-26 12:06:14 打赏
4楼
你这么理解也没错,但是要格外注意一点,之所以使用空指针,要注意具体函数中使用不同强制转换时传递地址的真正含义,有时候是传递消息的地址,有时候传递的是消息头的地址,这里有一点点技巧。

助工
2013-06-26 13:44:09 打赏
5楼
我还有点不明白的地方,消息头好像没有用到的地方啊

菜鸟
2013-06-27 11:56:26 打赏
6楼
消息头由系统内核来维护,你只需要为每条消息留出一个消息头的空间就行了。

高工
2013-06-27 12:05:55 打赏
7楼

明白了,这个东西是给内核用的。咱不用管。只管按照例子那样写就行了

PS:两位一线工程师亲自回答俺的问题,受宠若惊啊!



高工
2013-06-28 12:28:32 打赏
8楼

在uTenux论坛找到了更详细的介绍

http://www.tecoss.org/viewthread.php?tid=4617&extra=page%3D1


之前http://www.tecoss.org/viewthread.php?tid=4180&extra=page%3D1这个帖子提到过邮箱机制。接下来再重点说一下邮箱中用到的指针结构。
在邮箱机制中有一个特殊的结构——T_MSG,他只有一个成员变量msgque[1](为什么是数组形式的变量,看着真奇怪,先不管它!),msgque[1] 是一个VP也就是void *类型。T_MSG可以看做是一个邮箱消息头的标准结构,还有一个带优先级的T_MSG_PRI,可以称为邮箱消息头的带有优先级信息的特殊结构,当然用 户也可以自定义其他结构,比如例程中的U_MSG,但是这些结构都有一个共同点,就是它作为消息头必须位于一条消息的开始的区域,而且它必须以T_MSG 作为开始,用户不能对其进行任何修改,因为T_MSG要由OS亲自维护,这样邮箱中的所有消息才能成为一个队列的形式整体存在。

对于一个void*类型的指针来讲,如果你用到别人给它赋值或者类似的操作,编译器就会因为不知道它所指定的空间大小而报错,我们看看内核中哪里涉及到这 些操作,void*在什么地方被强制转换了。以tk_mbximpl.c中的tk_snd_mbx_impl(ID mbxid, T_MSG *pk_msg)函数为例:
SYSCALL ER tk_snd_mbx_impl( ID mbxid, T_MSG *pk_msg )/*此处无论传入的是什么类型的pk_msg指针,说白了就是要消息的起始地址。如果在此函数中你想添加一条操作将消息打印输出,你可能做不到,想想为什么?:)*/
{
MBXCB *mbxcb;/*这是一个MBXCB类型的指针变量,mbxcb可以用来存放一个指向MBXCB类型的指针*/
TCB *tcb;/*这是一个TCB类型的指针变量,tcb可以用来存放一个指向TCB类型的指针*/
ER ercd = E_OK;/*这是一个错误代号变量,默认为‘正确’*/

CHECK_MBXID(mbxid);/*检查一下邮箱ID是否合法,即大于等于1,小于配置的最大值*/

mbxcb = get_mbxcb(mbxid);/*取当前的邮箱控制块*/

BEGIN_CRITICAL_SECTION;/*进入临界区,关中断*/
if (mbxcb->mbxid == 0) {/*检查邮箱控制块中的mbxid是否非法*/
ercd = E_NOEXS;
goto error_exit;
}

if ( (mbxcb->mbxatr & TA_MPRI) != 0 ) {/*检查邮箱控制块中的mbxatr是否支持优先级*/
if ( ((T_MSG_PRI*)pk_msg)->msgpri <= 0 ) {/*如果支持优先级,检查pk_msg的优先级是否合法,注意这里有一个强制类型转换,如果这里没有使用T_MSG_PRI类型的消息头,可能会出现未知错误*/
ercd = E_PAR;
goto error_exit;
}
}

if ( !knl_queue_isempty(&mbxcb->wait_queue) ) {/*如果有任务在队列中等待邮箱消息,那么直接将邮箱消息挂到任务控制块中去,然后释放该任务*/
/* Directly send to receive wait task */
tcb = (TCB*)(mbxcb->wait_queue.next);
*tcb->winfo.mbx.ppk_msg = pk_msg; /*推了一下,感觉这里有问题,回头再看,也可能我错了*/
knl_wait_release_ok(tcb);

} else {/*否则,将消息放到等待队列*/
/* Connect message to queue */
if ( (mbxcb->mbxatr & TA_MPRI) != 0 ) {/*如果支持优先级,那么根据优先级将消息插入到合适的位置中去*/
/* Connect message to queue following priority */
knl_queue_insert_mpri((T_MSG_PRI*)pk_msg, &mbxcb->mq_head);
} else {
/* Connect to end of queue */
nextmsg(pk_msg) = NULL;
if ( headmsg(mbxcb) == NULL ) {/*如果不支持优先级,那么将消息放到邮箱消息队列的末尾*/
headmsg(mbxcb) = pk_msg;
} else {
nextmsg(mbxcb->mq_tail) = pk_msg;
}
mbxcb->mq_tail = pk_msg;
}
}

error_exit:
END_CRITICAL_SECTION;

return ercd;
}

观察一下,不难发现,只有pk_msg强制类型转换赋值给其他成员的操作,而没有别人赋值给pk_msg或者使用pk_msg传递消息的操作,想想为什么?


共8条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]