This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] 编译器/66AK2G12:如何解决多文件工程中的未定义符号链接器错误?

Guru**** 2595805 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/964943/compiler-66ak2g12-how-to-resolve-an-undefined-symbol-linker-error-in-a-multi-file-project

器件型号:66AK2G12

工具/软件:TI C/C++编译器

大家好、我在编译多文件项目中的一些基本 C++代码时遇到了问题。  

我在 C++中使用面向对象的技术。 此项目总共有三个文件:

VecN.hpp 和 VecN.cpp 定义了 A 类及其成员函数的实现。

main.cpp 是实例化对象并使用其成员函数执行某些操作的主文件。

随附了完整的构建日志副本。

您能在代码中发现我的错误吗? 我怀疑它与链接顺序和链接器设置有关、因为我已经成功使用 cygwin 中的 g++ v10.2.0和简单的 Makefile 来编译类似的代码。   

e2e.ti.com/.../1376.build_2D00_log.txt

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    这个问题很可能首先出现在一个较大的项目中、然后您将其分解为一个更小的项目、从而更清楚地表明了这个问题。  谢谢!  请提交此较小的项目。  按照文章 共享工程中的说明创建工程的 zip 文件。  然后将该 zip 文件附加到您的下一个帖子。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好、George。

    感谢你的答复

    我已将项目缩减为最简单的形式、并且仍然能够在新项目中重新创建问题。 然后、按照您提供的指导准则导出并压缩了该文件。

    作为额外的步骤、我在 Ubuntu 虚拟计算机中导入了生成的项目、但遇到了相同的错误。  

    e2e.ti.com/.../8713.test_2D00_project.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    当模板函数 0和  iszero 的声明 从 VecN.cpp 移动到 VecN.hpp 时、链接器错误不再出现。

    为什么不能将模板类的定义与其声明分开,并将其放入.cp 文件中? 解释尝试此更改的原因。

    不确定是否有更好的解决方法。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您已正确识别问题及其解决方案。

    模板不是对象的定义、而是编译器可以从中构造对象定义的蓝图。

    模板 
    void VecN <_Tp, N>:zero()
    {
    for (unsigned i=i;<N; i++) _a[i]= 0; } 0
    

    此代码未定义 VecN :ZERO 函数。 相反、它提供了蓝图、以便在遇到模板实例化时定义该函数。 由于在 Vecn.cpp 中未遇到此实例化、因此未定义任何函数。 因此、程序无法链接。

    与非模板成员函数不同,不应将模板类成员函数的定义放在另一个源文件中。 它们应该位于.HPP 文件中。

    有一个功能可以让您执行此操作、但我不确定它会有多大帮助、并且在一个较大的项目中会特别混乱、在这个项目中、VecN 以许多不同的方式实例化:"外部模板"的概念。


    https://en.cppreference.com/w/cpp/language/class_template

    在.HPP 中、您可以定义模板类、然后编写语句'extern template VecN '。 这会告诉编译器 VecN 有一个定义 可供程序使用、但它将在其他地方明确定义。

    然后,在 VecN.cpp 文件中,为::zero 和::iszero 定义模板类成员函数,然后编写语句'template VecN ;'。 这条被称为显式实例化的语句指示编译器定义类 VecN Vecn.cpp 中的所有成员函数。 由于::zero 和::iszero 的定义是可用的,因此它们也被定义。

    不过,我建议您不要在模板类成员的标题之外定义模板类成员函数。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您的回答。 我对模板和 C++的使用非常熟悉。 我从这方面得到的结果是:

    1. 模板是类或函数的定义。 编译器仅在遇到声明类/函数的实例时生成代码。  
    2. 若要在编译器遇到实例时生成代码、它必须具有可用的声明-因此、'memember functions'的实现应该出现在.HPP 文件中。

    感谢你的帮助

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您对这种情况的理解是正确的。  话虽如此,我想提醒您使用某些术语。

    具体而言、术语声明定义意味着非常特殊的事情。  请在 本 C 常见问题解答中阅读相关内容。  尽管这是 C 常见问题解答、但这些术语在 C++中的含义是相同的。   

    谢谢、此致、

    乔治