重构遗留C代码 – 使用extern声明来帮助拆分模块(潜在的链接和运
我正在重构一些旧的遗留代码,用C语言编写.代码紧密耦合,我正在努力将其重构为清晰的逻辑,松耦合模块.
在我早期的迭代中,我设法确定了逻辑模块 – 然而紧密耦合导致了我的问题,因为许多函数都对系统的其他部分有深入的了解. 我打算解决这个问题的方法是使用extern声明.希望下面的伪代码解释了这种情况: 假设我有两个逻辑上独立的模块Foo和FooBar.每个模块都要构建到一个单独的库中(FooBar模块依赖于Foo模块). /*######################################*/ /* Foo Module */ /*######################################*/ /* Foo.h */ #ifndef FOO_MODULE_H #define FOO_MODULE_H void foo(int id); int do_something(); ... #endif /* FOO_MODULE_H */ /* Foo.c */ #include "Foo.h" extern int foobar(); /* defined in FooBar module (a separate library) */ void foo(int id){ int var; switch (id){ case 1: var = do_something(); break; case 2: /* the module that gets here,has the required functions defined in it */ var = foobar(); } return var; } /*###############################*/ /* FOOBar module */ /*###############################*/ /* FooBar.h */ #ifndef FOOBAR_MODULE_H #define FOOBAR_MODULE_H #include "Foo.h" int foobar(); void do_something_else(); ... #endif /* FOOBAR_MODULE_H */ /* source file */ int foobar(){ return 42; } void do_something_else(){ int ret = foo(2); printf("Function returned: %d",ret); } 这是将现有代码重构为逻辑上独立的模块的有效方法,同时允许链接到libfoo.so和libfoobar.so的可执行文件继续正常工作吗? 我的基本假设是链接到libfoo.so的模块将无法解析foobar() – 但这应该没问题,因为它们不需要该函数,因此它们永远不必调用它.另一方面,对于链接到libfoobar.so的模块,当它们调用foo()时,`foobar()将被解析(函数定义在模块中). 我上面描述的方案是否会像我期望的那样工作,或者是否有一些我失踪的问题? 解决方法
我尝试将你的文件编译成共享库,然后使用它们(我使用cygwin).
这是为了Foo: cm@Gregor-PC ~/src $gcc -I. -c --shared -o libFoo.so Foo.c 使用bin util nm,你可以检查符号(grep为’foo’来限制输出) cm@Gregor-PC ~/src $nm libFoo.so | grep foo 0000000a T _foo U _foobar 它给出了一个偏移量并且表示终止的’T’告诉你符号是在lib中定义的. 现在,FooBar lib必须与Foo链接才能拥有foo符号 cm@Gregor-PC ~/src $gcc -I. -L. --shared -o libFooBar.so FooBar.c libFoo.so cm@Gregor-PC ~/src $nm libFooBar.so | grep foo 61f0111e T _foo 61f010e0 T _foobar 有了这个,我只能编译FooBar并将foo作为已知符号: cm@Gregor-PC ~/src $gcc -I. -o tst1 tst1.c libFooBar.so cm@Gregor-PC ~/src $./tst1 Function returned: 42 所以似乎工作正常. 您可以通过包含仅包含公共数据类型,导出函数原型(声明为extern)甚至公共全局变量或常量的头文件来改进模块化C代码的方法.这样的头文件声明了模块的接口,并且必须包含在使用模块的地方. 在模块章节中,精彩的书籍‘Functional C’(Hartel,Muller,1997,Addison Wesley,link)对此进行了更详细的解释. 好处是您的依赖关系更清晰(在源文件中包含),并且您不必在Foo源中具有那种难看的extern声明. 对于你的例子: /* Foo.h */ extern int foo(int id); /* exported to FooBar */ /* FooBar.h */ extern int foobar(); /* export to Foo */ extern void do_something_else(); /* export to tst1 */ /* Foo.c */ #include <Foo.h> #include <FooBar.h> int do_something() { return 11; } int foo(int id){ int var; switch (id){ case 1: var = do_something(); break; case 2: /* the module that gets here,has the required functions defined in it */ var = foobar(); } return var; } /* FooBar.c */ #include <stdio.h> #include <Foo.h> #include <FooBar.h> int foobar(){ return 42; } void do_something_else(){ int ret = foo(2); printf("Function returned: %d",ret); } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 控制连接数量和密码保护-flashcom教程 密码保护
- 什么是CDATA段 <![CDATA[ 内容 ]]>
- sqlite 与ParseDateTime直接的冲突
- 【原】移植uboot到MPC8313E-RDB---【一】MPC8313ERDB.h文件
- AJAX学习
- swift3 – FileManager replaceItemAt()导致EXC_BAD_ACCESS
- F2FS – A New Flash File System for Mobile Devices – E
- 4.5 Swift中for in 循环语句
- hello react.js
- ruby-on-rails-3 – 如何在Rails 3.2中验证其父模型范围内嵌