隐藏结构成员

Hiding Struct Members

我知道以前可能有人问过这个问题,但我想用我的方法来解决这个问题并征求意见或可能是更好的方法。 我有三个文件 a.h a.cmain.c 关于结构的函数原型将在 a.h 中,而实现将在 a.c 中并从 [=16 中调用=] 结构会很简单,看起来像这样

struct ctx{
    int x;
};

我希望 a.c 能够操纵结构的内容,但防止 main 知道里面的内容。所以我想将结构定义放在 a.c 而不是 a.h 中,并将 struct ctx; 作为原型放在 a.h 中 这可以工作,但是 ctx 不能再在 main.c 中的堆栈上分配,因为编译器不知道要分配的大小。 所以这引出了我的第一个问题:有没有办法在不知道结构定义的情况下将结构本地分配到堆栈。

所以我假设如果在堆栈上不可能,那么也许我可以通过创建一个 returns 指针的简单初始化函数来将它传递到堆上。这确实有效,但会使过程过于复杂吗?

a.h

#ifndef a_h
#define a_h

#include <stdio.h>
#include <stdlib.h>
struct ctx;
int incctx(struct ctx* c);
struct ctx* initctx(void);
void destroyctx(struct ctx* c);
#endif /* a_h */

a.c

#include "a.h"
struct ctx{
    int x;
};
int incctx(struct ctx* c){
    return ++c->x;
}
struct ctx* initctx(){
    struct ctx* c =  malloc(sizeof(struct ctx));
    c->x = 0;
    return c;
}
void destroyctx(struct ctx* c){
    free(c);
}

main.c

#include "a.h"

int main(){
    struct ctx* c = initctx();
    printf("%d\n",incctx(c));
    printf("%d\n",incctx(c));
    printf("%d\n",incctx(c));
    destroyctx(c);
    return 0;
}

这种设计解决了一些缺点的问题。 1:如果我想让部分结构可见而不是整个结构怎么办? 2:如果我希望结构定义可用于其他文件,比如 b.hb.c,我是否必须重新定义结构?你们有没有更简洁的设计?我知道有些人说您可以在结构中放置一个 void* 而不是特定类型,然后将它们标记为任意名称,但我认为这不是一个可行的解决方案。

对于可见性问题,您可以以类似继承的方式使用两个结构。

首先,您拥有在头文件中定义的 public 结构,您的 API 处理指向的指针:

struct ctx
{
    // Public data
};

然后在源文件中创建一个私有结构,其中 public 结构是第一个成员:

struct private_ctx
{
    struct ctx ctx;  // The public part of the structure

    // Followed by private data
};

在 API 内部使用 private_ctx 结构,而使用 API 的代码只会使用 public ctx 结构。

像这样的嵌套结构类似于继承,private_ctx结构是一个ctx结构。您可以创建一个 private_ctx 结构和 return 指向它的指针适当地转换为 ctx 结构。

以下是有关如何创建结构的示例:

struct ctx *create_struct(void)
{
    // Allocate the private structure, which contains the public structure
    struct private_ctx *data = = malloc(sizeof *data);

    // Return the public part of the structure
    return (struct ctx *) data;
}

通过反向转换使用私有数据同样容易:

void use_data(struct ctx *data)
{
    struct private_ctx *private_data = (struct private_ctx *) data;

    // Here the private data can be used...
}

抽象隐藏可以通过让您的模块将指向结构的指针传递给 main 并让您的模块对其执行所有操作来实现。那么 main 只知道 ctx 是一些空数据类型(指针)就足够了,例如

// main.c

void *initctx(void);
int incctx(void *c);

int main(void)
{
    void *ctx= initctx();
    int i= incctx(ctx);
    //....
}

您想将整个结构隐藏在 a.c

分配结构时,不要 return 指向它的指针,而是 return 句柄,它可能是您在 a.c 中维护的结构数组的索引

如果您想将结构的任何部分暴露给外部,请提供类似 getSomething(int handle) 或 setSomething(int handle) 的函数。

open(),returning 一个 int 使用这种方法,而不是 fopen(),后者 return 是一个文件 *