我想让我的项目更加模块化,以便在删除其中一个模块时没有模块间依赖关系。
例如,如果我将我的过程中的代码分成多个目录,比如X,Y和Z,那么X中的数据结构不应该由Y和Z中的数据结构直接访问,反之亦然,那么我需要一些内部通信机制X,Y和Z.
由于我使用C编码,是否有人可以建议样本项目或设计考虑因素?
这通常归结为API设计。 我认为有用的几件事:
libfoo.h
int (*libfoo_callback)(void *arg, const char *name, int id); /** * Iterate over all known foobars in the system. */ int libfoo_iterate_foobars(libfoo_callback cb, void *arg);
libfoo.c
#include "libfoo.h" /* Private to libfoo.c */ struct foobar { struct foobar *next; const char *name; int id; }; /* Don't make this globally visible */ static struct foobar *m_foobars; int libfoo_iterate_foobars(libfoo_callback cb, void *arg) { struct foobar *f; for (f = m_foobars; f != NULL; f = f->next) { int rc = cb(f->name, f->id); if (rc <= 0) return rc; /* Stop iterating */ } return 0; }
some_consumer.c
#include #include "libfoo.h" struct cbinfo { int count; }; static int test_callback(void *arg, const char* name, int id) { struct cbinfo *info = arg; printf(" foobar %d: id=%d name=%sn", info->count++, id, name); return 1; /* keep iterating */ } void test(void) { struct cbinfo info = { 0 }; printf("All foobars in the system:n"); libfoo_iterate_foobars(test_callback, &info); printf("Total: %dn", info.count); }
在这里,我展示了一个跟踪一些foobars的libfoo。 我们有一个消费者,在这个例子中,只是想显示所有foobars的列表。 这个设计的好处:
要真正实现模块化,您将需要两件大事:
具体情况将根据您的目标平台,模块化需求,预算等因素而有很大差异。
对于#1,您通常会有一个模块注册系统,其中一些组件跟踪已加载模块的列表,以及有关生成和使用内容的元信息。
如果模块可以调用其他模块提供的代码,则需要一种方法使其可见。 这也将用于实现2.以Linux内核为例 - 它支持可加载内核模块 ,以便将新function,驱动程序等添加到内核中,而无需将其全部编译为一个大型二进制文件。 模块可以使用EXPORT_SYMBOL
来指示特定符号(即函数)可供其他模块调用。 内核跟踪加载哪些模块,导出哪些函数以及哪些地址。
对于#2,您可以利用操作系统的共享库支持。 在Linux和其他Unices上,这些动态库是ELF( .so
文件),它们由动态加载程序加载到进程的地址空间中。 在Windows上,这些是DLL。 通常,在您的流程开始时,会自动处理此加载。 但是,应用程序可以利用动态加载程序显式加载其选择的其他模块。 在POSIX上你可以调用dlopen()
,在Windows上你可以使用LoadLibrary()
。 这两种函数都会为您返回某种句柄 ,这样您就可以对模块进行进一步的查询或请求。
然后可能需要您的模块(按照您的设计)导出codingfreak_init
函数,该函数在首次加载模块时由您的应用程序调用。 然后,此函数将对您的框架进行额外调用,或返回数据以指示它需要和提供的工具。
这些都是非常一般的信息,应该让你的车轮转动。
在你开始编码之前我会设置一个“公共”API。 然后,代码仅使用每个模块外部的API。 不要作弊; 仅使用公共API(尽管API可以根据需要发展)。 它可以帮助尽可能多地处理面向对象语言中的对象之类的数据结构,以及像对象方法那样的公共API。 尽可能避免在模块外部直接使用内部数据结构字段; 虽然如果它们是API的一部分,返回定义良好的数据结构是可以的。 只是不要直接在它们来自的模块之外修改它们。 如果您花费大量时间预先设计接口,则可以创建一个非常易于维护的项目。
以上就是c/c++开发分享我如何在C模块化设计?相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/562660.html