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

时间:2019-01-12 08:45:57

标签: c adt information-hiding

我了解到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*/
}

现在,除了Payload_Manager.c中的函数外,我不希望其他文件知道类型“ ATEIS_Payload_s”。因为只有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中实现此概念。另外,我很可能在此程序中滥用了这个概念。

2 个答案:

答案 0 :(得分:2)

您正在向错误的目标射击。

您的目标不应该是将每个指针变成void*, 因为那样您就放弃了C编译器可以提供的所有(有限)类型安全。

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

this文章中介绍了操作方法。

答案 1 :(得分:1)

您的示例很长,因此我将尽力帮助您了解信息隐藏和adts的概念。

在谈论信息时,要记住的一件事是,如果给外部用户提供h文件,那么他就可以使用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;

我不确定为什么您的create函数返回一个(void *)。 考虑一下。如果用户使用 void * Payload_Manager_Ctor 功能,则他希望获取有效负载。 同样,您必须在h文件的c文件中声明所有用户预期的无静态函数。因此现在它们可以按外部用户的意愿使用。

简而言之,H文件只需要具有其必须具有的所有内容,即可使用这些功能,而无需了解其工作方式的秘诀。

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

考虑一个简单的链表或向量。您可以列出一个唯一的数据类型为int的列表。但是此实现现在限制了代码的可用性。如果您创建一个节点,而不是为数据携带void *,则对于用户可以在该列表中放置的内容没有任何限制。他可以存储指向结构,数组和chars ext的指针。列表的功能保持不变,数据将保存在列表中。但是什么样的数据呢?用户需要哪种类型。由于用户知道他已存储的内容,因此他将知道如何正确提取它并进行操作。

我希望这会有所帮助,祝你好运!