隐藏结构成员
Hiding Struct Members
我知道以前可能有人问过这个问题,但我想用我的方法来解决这个问题并征求意见或可能是更好的方法。
我有三个文件 a.h
a.c
和 main.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.h
和 b.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 是一个文件 *
我知道以前可能有人问过这个问题,但我想用我的方法来解决这个问题并征求意见或可能是更好的方法。
我有三个文件 a.h
a.c
和 main.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.h
和 b.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 是一个文件 *