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

         VP  msgque[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 跳转至

回复

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