模块化编程
在一个庞大的程序中避免不了会包含多个程序模块,各个模块按照功能分类、数据和分装、接口定义、编程语言和库支持来进行划分,各个程序模块可以通过多线程的方式运行在程序中。
- 功能分类:在高级编程中,以程序的各个功能作为关注点,模块划分就是分离关注点的结果。一个模块可以使用另一个模块来实现自己的功能,但除此之外的模块之间最好交互没有。
- 数据和封装:在理想的精密编程中,每个模块都可以隐藏成一个黑盒子,只需要了解模块提供的功能,不需要具体实现该功能的策略和方法,即提供机制而不是策略。
- 接口定义:为了实现模块之间的解耦,模块需要定义明确的接口,以便其他模块可以通过这些接口来调用它提供的功能。接口定义包括函数原型、函数参数、函数返回类型等。
- 编程语言和库支持:在自定义编程中,可以使用不同的编程语言和库来实现模块。例如,在C++和D语言中,可以使用命名空间来实现自定义编程。在Linux下,可以使用库来实现多线程编程,并使用静态库、动态库、可执行文件等方式来实现自定义编程pthread
参见
- 程序设计思想与方法:https://www.kancloud.cn/wizardforcel/sjtu-cs902-courseware
- 模块化编程技巧:https://blog.csdn.net/yanlaifan/article/details/124785266
- 如何正确模块化: https://blog.csdn.net/quantum7/article/details/130920916
--------------------------------------------------扯远了,回归正题--------------------------------------------------
在程序中各个模块在程序启动后以线程并发的方式run,在各模块中链接库文件时,但链接了同一个库文件或者不同库中有同名的符号造成符号冲突。
预想中:
实际上:
符号冲突
符号冲突原理
预想实施逻辑:
实际实施结果:
过程:
- 在编译过程中,每个模块都会生成一个目标文件(.o文件),其中包含了该模块的代码和数据。
- 在链接过程中,链接器将所有目标文件合并成一个可执行文件或动态链接库。
- 在合并过程中,链接器会检查每个目标文件中定义的符号,把它们与其他目标文件中的符号进行比较。
- 如果发现多个目标文件中定义了名称相同的符号,链接器会报告符号重复的错误,并停止链接过程。
- 如果符号重复的错误发生在动态链接库中,那么该库将无法加载,导致程序无法正常运行。
解决方法
- 重命名符号:如果您有权限修改动态库源代码,可以修改其中的符号名称,小区与其他库发生冲突。这个方法虽然修改可行,但可能需要大量源代码,不太适合快速解决问题。
- 使用命名空间:如果您在编写自己的库时使用了命名空间,可以通过命名空间来避免与其他库发生符号冲突。但是,如果使用的库没有使用命名空间,这个方法就无法使用。
- 修改链接顺序:您可以通过链接时的顺序来解决符号冲突。将相同名称的符号定义放在前面的库链接时先被加载,从而解决符号冲突问题。但这个方法不可靠,因为链接顺序的变化可能导致其他问题。
- 隐藏符号:如果您使用隐藏编译器支持符号功能,可以使用该功能来避免符号冲突。符号隐藏可以将符号标记为仅在当前库中可见,从而避免与其他库中的符号冲突。但是这个方法需要编译器的支持,并且需要在编译时进行配置。
- 链接时忽略符号冲突:在某些情况下,您可以通过在链接时忽略符号冲突来解决问题。这个方法可以通过编译选项来实现,但需要详细使用,忽略符号冲突因为可能导致程序行为异常或崩溃了。
解决方法具体实现参加如下文章:
- https://blog.csdn.net/qq_29426201/article/details/113092051
- https://just4coding.com/2022/11/22/linux-symbol/
- https://yang.observer/2021/01/22/cpp-symbol-conflict/
- https://www.cnblogs.com/langqi250/p/7516230.html
- https://blog.csdn.net/weixin_44834554/article/details/127662876
- https://blog.csdn.net/weixin_45449806/article/details/129114860