【问题标题】:Can we retrieve back an object after converting it to (char *)我们可以在将对象转换为 (char *) 后取回一个对象吗
【发布时间】:2015-03-22 03:58:49
【问题描述】:
        msg->msgType = JOINREPLY;
        memcpy((char *)(msg+1), &memberNode->addr.addr, sizeof(memberNode->addr.addr));
        memcpy((char *)(msg+1) + 1 + sizeof(memberNode->addr.addr), &memberNode->memberList, sizeof(memberNode->memberList));

这是我想通过调用另一个函数从一个函数发送的消息,即send((char *)msg, msgsize);

msg的数据结构是

enum MsgTypes{
    JOINREQ,
    JOINREPLY,
    DUMMYLASTMSGTYPE,
    HEARTBEAT
};

typedef struct MessageHdr {
    enum MsgTypes msgType;
}MessageHdr;

vector<MemberListEntry> memberList;是memberList的定义,可以看到memberList是一个MemberListEntry类型的向量,MemberListEntry有自己的数据。

int id;
short port;
long heartbeat;
long timestamp;

由于我将完整的 memberList 转换为 (char *),是否可以再次将 (char *) 转换为 memberList 或 MemberListEntry 类型并对其进行迭代??

        MemberListEntry *ml;
        ml=(MemberListEntry *)malloc(sizeof(MemberListEntry));
        for(char *j=finalData; i < (int)string(finalData).length(); j = (char *)(j+ sizeof(MemberListEntry))){
            ml= (MemberListEntry *)j;
            i+=sizeof(MemberListEntry);


            idR=ml->getid();
            portR=ml->getport();
            heartbeatR=ml->getheartbeat();
            //Do some stuff
        }

“finalData”是我在去掉 msgType 和我存储的地址后得到的数据,将指针指向我以 char 格式存储 memberList 的位置。

【问题讨论】:

    标签: c++ pointers casting char


    【解决方案1】:

    您需要在邮件标题中包含一个字段,指示邮件包的整个大小。

    可能是这样的:

    typedef struct MessageHdr {
        enum MsgTypes msgType;
        unsigned int msgLength;
    } MessageHdr;
    

    存储在 msgLength 字段中的实际值取决于约定,例如它可以不同于整个消息包的大小或减去标题的大小,或者只是MemberListEntrys 的计数。使用你喜欢的任何东西。

    您使用send((char *)msg, msgsize); 通过 tcp 套接字发送。但是,您的对等方无法找出重要的 msgsize 值来重建消息数据,除非您明确将其作为消息头的一部分发送。

    那么重建它们应该是微不足道的。

    首先你应该弄清楚你的消息包中有多少条目。然后你分配一个该大小的新向量。最后你memcpy把所有数据都放到了新向量中,一切都应该没问题。


    原则 #1:您无法从任何地方获取信息。

    sizeof 有效,因为编译器知道大小。 它们是由规范、平台或您#included 的头文件预定义的。它们是固定的。而且他们永远不会改变。

    .length()之所以有效,是因为std::vector在场景下为你保留了长度信息。你可以自己查看它们对应的头文件。

    简而言之,它们都不是来自一些花哨的魔法,可以自动找出任意内存区域中包含的内容。

    在您的情况下,信息 - “实际元素计数” - 至关重要。并且它必须可供对等方访问才能重建数据结构。

    原则 #2:其中包含指针的数据结构不能直接通过网络发送。

    指针只在当前进程中有效。您不能盲目地通过网络发送指针。所以发送你聪明的std::vector 也不起作用。虽然std::vector 本身具有固定大小,您可以将sizeof 应用于它,但它在内部使用指针来保存可以动态更改的实际数据。


    嗯,您真正需要的是某种数据编组/对象序列化。您需要将数据转换为适合网络传输的某种表示形式,然后再将它们转换回来。在 C++ 领域,你必须自己做。没有魔法。

    如果您觉得实现这样的事情真的很无聊,请考虑使用一些高级语言来为您处理对象序列化。例如,Javascript 原生支持著名的 JSON 格式,这种格式在数据交换方面非常出色。或者您可以使用 C#,它具有快速高效的强类型二进制序列化程序。

    【讨论】:

    • 这一切都可以完成,但我正在寻找一些代码来从 (char *) 转换回对象,正如我上面提到的,memberList 是一个向量,MemberListEntry 类的类型。并且可以添加或删除向量的元素。所以长度不能固定。此外,它总是可以通过 .length() 或 sizeof 以适当的逻辑找到。条目都在代码的第一部分中提到
    • 如果我们在消息包之外发送msgsize,为什么对端不能从msgsize中计算出数据的大小?为什么我不能按照我想做的方式去做?
    • 你应该知道一件事:一个 char * 是一个指针,它指向一块未知大小的内存,除非有办法计算出大小。因此,无论您做什么,都需要将“数据大小”信息保存在某处,并确保您的对等方可以访问此信息。
    • std::vector 知道它有多少元素,因为它与您拥有的原始数据一起维护该信息memcpy-ed。为您完成这些繁琐工作的是标准库,而不是可以自动知道原始 char * 中包含多少数据的魔法。
    • 我在某处读到它可以转换回对象,因为它们都是指针......并指向存储它的内存位置
    【解决方案2】:

    如果您需要使用 char* 传输数据,只要您知道数据的大小,您可以简单地将数据重铸回其原始形式,假设没有 TCP 阻止的数据变形或转换。

    char* 实际上是一种伪装的数组,因为数组实际上只是相邻存储在内存中的数据块。在 C 中:

    array[1] and 1[array]是一样的,都是访问数组地址加1的数据。

    因此,您的数据刚刚“未格式化”为原始数据块。如果您使用强制转换为原始形式来给它类型,一切都应该没问题。

    如果您的数据包含指针,那您就完蛋了。现在你没有原始的内存地址系统可以参考,那么如何定位数据呢?除非您也复制内存地址,否则一旦指针跨系统,您将无法访问它们。

    【讨论】:

    • 这里的一个重要警告是,这仅适用于相对琐碎的结构(例如询问者)。如果你的结构包含指针,你需要处理那个特殊的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    相关资源
    最近更新 更多