这种情况下如何实现信息隐藏呢?

How to achieve information hiding in this case?

我了解到 ADT 是一个重要的概念,我正在学习这项技术。

这里有一个问题,我不知道如何处理。

Payload_Manager.h

typedef struct __attribute__((__packed__))
{
    u32 Addr;
    u16 Cmd;
    u16 Len;
    u8 Data[0];
}ATEIS_Payload_s;   //payload

Payload_Manager.c

#include "Payload_Manager.h"
void* Payload_Manager_New(int size)
{
    return (ATEIS_Payload_s*)malloc(size);
}
void* Payload_Manager_Ctor(void* _this, u32 ip, u16 cmdID, u16 dataLen, char* rxBuf)
{
    ATEIS_Payload_s* this = (ATEIS_Payload_s*)_this;
    this->Addr = ip;
    this->Cmd = cmdID;
    this->Len = dataLen;
    memcpy(this->Data, rxBuf, dataLen);
    return this;
}
void* Payload_Manager_Dtor(void** _this)
{
    free(*_this);
    *_this = NULL;
    return *_this;
}

DNM_Manager.h

void* DNMManager_Ctor(void* _this,
                      void* name, 
                      u32 ip, 
                      u32 sn, 
                      u32 subMask);

DNM_Manager.c

typedef struct
{
    u32 Addr;
    u32 SerialNo;
    u32 SubnetMask;
    char Name[NAME_SIZE];
}DNM;

static DNM DNMSet[SET_SIZE];
static DNM DNMTemp;

void* DNMManager_Ctor(void* _this, 
                      void* name, 
                      u32 ip, 
                      u32 sn, 
                      u32 subMask)
{
    DNM* this = (DNM*)_this;
    memcpy(this->Name, name, NAME_SIZE);
    this->Addr = ip;
    this->SerialNo = sn;
    this->SubnetMask = subMask;
    return this;
}

CmdHndlr.c

#include "Payload_Manager.h"
#include "DNM_Manager.h"
int main(void){
    ATEIS_Payload_s* pl_p = NULL;
    void* DNM_temp = NULL;

    pl_p = OSTaskQPend(0, OS_OPT_PEND_BLOCKING, &msgSize, &ts, &err);   //wait for a message

    /*This works properly*/
    DNM_temp = DNMManager_Ctor(DNM_temp,
                               &pl_p->Data[NAME],
                               pl_p->Addr,
                               *(u32*)&pl_p->Data[SN],
                               *(u32*)&pl_p->Data[SUBMASK]);
    /*following code is omitted*/
}

现在,我不希望其他文件知道 "ATEIS_Payload_s" 类型,Payload_Manager.c 中的函数除外。因为只有 Payload_Manager.c 中的函数处理类型 "payload".

换句话说,我想将 CmdHndlr.c 中的代码更改为:

//#include "Payload_Manager.h"    /*no need anymore*/
#include "DNM_Manager.h"
int main(void){
    void* pl_p = NULL;    //programmer no need to know what type pl_p is
    void* DNM_temp = NULL;

    pl_p = OSTaskQPend(0, OS_OPT_PEND_BLOCKING, &msgSize, &ts, &err);   //wait for a message

    DNM_temp = DNMManager_Ctor(DNM_temp, pl_p);    //DNM_Manager_Ctor will deal with it.
    /*following code is omitted*/
}

这里有一点值得注意:函数 "DNM_Manager_Ctor" 同时处理类型 "DNM" 和 "ATEIS_Payload_s"。

这是通过让 DNM_Manager_Ctor 知道类型 "DNM" 和 "ATEIS_Payload_s" 来实现的。这意味着将 DNM_Manager.c 更改为:

typedef struct
{
    u32 Addr;
    u32 SerialNo;
    u32 SubnetMask;
    char Name[NAME_SIZE];
}DNM;
typedef struct __attribute__((__packed__))    //oops, already declared in somewhere else. Is this valid?
{
    u32 Addr;
    u16 Cmd;
    u16 Len;
    u8 Data[0];
}ATEIS_Payload_s;   //payload

void* DNMManager_Ctor(void* _this, 
                      void* _dest)
{
    DNM* this = (DNM*)_this;
    ATEIS_Payload_s* dest = (ATEIS_Payload_s*)_dest;

    /*following is omitted*/

    return result;
}

不知道这种方式是否有效。但是这种方式显然会降低模块化,即使它是有效的。

有没有更好的办法解决?

编辑:

我是面向对象的新手。我正在尝试在 C 中实现这个概念,尽管它非常粗糙。另外,我很可能在这个程序中误用了这个概念。

你射错了目标。

你的objective不应该是把每一个指针都变成void*, 因为这样你就放弃了 C 编译器可以提供的所有(有限的)类型安全。

相反,您的objective 应该向客户端隐藏结构的定义(即内部结构)。

this 文章中解释了如何执行此操作。

你的例子很长,所以我会尽力帮助你理解信息隐藏和广告的概念。

在谈论信息隐藏时要记住的是,如果您将您的 h 文件提供给外部用户,他将能够在不知道编码器如何 "made it happen" 的情况下使用您的 c 函数例如,在您的 Payload_Manager.h 中,用户不需要知道结构是如何构建的。他唯一需要的就是这个模块提供的功能。因此,编写此 h 文件的正确方法是首先将结构移至您的 c 文件,并且仅将该结构的 typedef 放入您的 h 文件中:

struct __attribute__((__packed__)) ATEIS_Payload_s
{
u32 Addr;
u16 Cmd;
u16 Len;
u8 Data[0];
};

在你的 h 文件中:

typedef struct ATEIS_Payload_s ATEIS_Payload_s;

我不确定为什么你的创建函数 returns a (void*)。 想一想。如果用户使用 void* Payload_Manager_Ctor 函数——他想获取有效负载。 此外,您必须在 h 文件中的 c 文件中声明所有用户预期的 none 静态函数。所以现在它们可以被外部用户按预期使用。

简而言之,H 文件只需要包含它必须包含的内容才能使用这些功能,而不是它们如何做事的秘诀。

现在关于抽象数据类型,使用它们的想法是,当唯一需要知道它们是什么的人是用户时。

想想一个简单的链表,或者一个向量。您可以制作一个列表,其中存储的唯一数据类型是 int。但是这个实现现在限制了代码的可用性。如果您创建一个节点,而不是为数据携带 void* ,则用户可以在该列表中放置的内容没有限制。他可以存储指向结构、数组、字符的指针。列表的功能保持不变,数据将保存在列表中。但是什么样的数据呢?无论用户需要什么类型。由于用户知道他存储了什么,他将知道如何正确提取和操作它。

希望对你有所帮助,祝你好运!!