提问人:S2G 提问时间:6/25/2023 最后编辑:S2G 更新时间:6/25/2023 访问量:56
在 C 语言中隐藏 init 结构并使用 init 函数
Hide init struct in C and use init function
问:
我正在编写一个结构类型定义来初始化一些功能(嵌入式微控制器编程)
但是,如果这个结构是init,那么整个结构就会崩溃,所以我决定编写一个函数来初始化结构并malloc内存,然后在函数返回中将指针发送回用户。如下代码所示:
//this is just a demonstration of what i want not the code
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int a;
int b;
}mystr;
mystr * init_str(int a, int b)
{
mystr * strinit = (mystr *)malloc(sizeof(mystr));
//for example no more than 10 is acceptable !!
if(a<10)
strinit->a=a;
else
strinit->a=10;
if(b<10)
strinit->b=b;
else
strinit->b=10;
return strinit;
}
void deinit_str (mystr * str)
{
free(str);
str=NULL;
}
int main()
{
mystr * strinit = init_str(5, 15);
printf("numbers are = a: %d , b: %d \n",strinit->a,strinit->b);
deinit_str(strinit);
}
这里输出的是 5 和 10
但是,该结构对用户仍然是可见的,他们可以忽略使用 init 函数并直接进入该结构并使用杀死此方法的整个 porpuse,例如以下代码:
//this is just a demostration of what i want not the code
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int a;
int b;
}mystr;
mystr * init_str(int a, int b)
{
mystr * strinit = (mystr *)malloc(sizeof(mystr));
//for example no more than 10 is acceptable !!
if(a<10)
strinit->a=a;
else
strinit->a=10;
if(b<10)
strinit->b=b;
else
strinit->b=10;
return strinit;
}
void deinit_str (mystr * str)
{
free(str);
str=NULL;
}
int main()
{
//IGNORE CREATE AND WRITE WHAT EVER
mystr strinit={
.a=5555,
.b=6969,
};
//THE NUMBERS ARE HIGHER THAN 10 AND NOT acceptable
printf("numbers are = a: %d , b: %d \n",strinit.a,strinit.b);
}
这里输出的是 5555 和 6969,这是错误的 如何限制结构的使用并只允许使用init函数进行创建
如果在 C 中没有办法做到这一点,我可以在 C++ 中做这样的事情吗?
答:
1赞
Ted Lyngmo
6/25/2023
#1
您可以将 设置为不透明类型,并将实现细节隐藏在文件中。这样做清楚地表明,除了使用您提供的函数之外,连接到此类型的数据不应以任何其他方式弄乱。struct
.c
例:
公共头文件:
typedef struct {
void *ptr;
} Handle;
Handle init_str(int a, int b);
void deinit_str (Handle h);
文件中的内部实现:.c
typedef struct { // never exposed in a public header file
int a;
int b;
} mystr;
Handle init_str(int a, int b) {
mystr *ms = malloc(sizeof *ms);
*ms = (mystr){.a = a < 10 ? a : 10,
.b = b < 10 ? b : 10};
return (Handle){.ptr = ms};
}
void deinit_str (Handle h) {
free(h.ptr);
}
在文档中,您只会提到库中的函数返回或采用 .Handle
当然,了解内部实现细节的人仍然可以解决这个问题,但这需要更多的努力,而且这样做的人肯定不会错误地这样做,并且应该为意外做好准备,如果你在下一个版本中更改了内部重复库。
评论
0赞
S2G
6/25/2023
谢谢!我以前从未使用过这个,我将测试它,然后提供反馈
1赞
Ted Lyngmo
6/25/2023
@S2G 不客气!我自己也使用过它,主要不是为了向用户隐藏实现细节,而是为了能够为 C++ 库提供 C 接口。C 编译器只能看到不透明的类类型,而 C++ 编译器可以看到两者并编译内部结构。效果很好。Handle
0赞
0___________
6/25/2023
为什么这么复杂。只需返回 void *指针
3赞
Ted Lyngmo
6/25/2023
@0___________这是为了添加一些类型安全性。当我自己在库中做这件事时,我发现当有许多类似类型的类型时,它可以帮助用户正确地做到这一点。如果犯了错误,得到一个“不兼容的参数类型”编译错误比崩溃更好:-)Handle
评论