有时,在编译对象文件的符号表(带有nm -aC file.o)中,有些明显被称为函数的转换单元(TU)不存在。可能是什么原因?
原因可能是:
(1)对调用进行了优化:不是针对下面的示例,而是使用-g编译的调试版本。
(2)对调用进行预处理和删除:对于下面的示例来说,在调用周围没有#
(3)别名或预处理后有另一个名称:不是针对下面的示例,而是在AOSP源代码中搜索了skia分支,没有相关的#define/typedef
(4)由于它是内联的,为了提高编译速度,不能在每一个称为它的TU中编译它。
(4-1)但是即使没有编译,它也至少会作为一个未定义的符号出现在对象文件中,稍后由链接器找到,但是下面的示例中根本没有这个符号。
(4-2)如果是这样的话,考虑到调用函数的所有TUs都是独立编译的,编译器如何决定何时编译内联函数?
的其他可能原因是什么?
一个例子是SkOTTable_name.cpp in AOSP10:
namespace {
bool BCP47FromLanguageIdLess(const BCP47FromLanguageId& a, const BCP47FromLanguageId& b) {
return a.languageID < b.languageID;
}
}
bool SkOTTableName::Iterator::next(SkOTTableName::Iterator::Record& record) {
...
// Handle format 0 languages, translating them into BCP 47.
const BCP47FromLanguageId target = { languageID, "" };
int languageIndex = SkTSearch<BCP47FromLanguageId, BCP47FromLanguageIdLess>(
BCP47FromLanguageID, SK_ARRAY_COUNT(BCP47FromLanguageID), target, sizeof(target));
...
}调用的实例化模板内联函数"SkTSearch“不是"nm -aC ./SkOTTable_name.o”的结果。顺便提一下,函数"SkOTTableName::Iterator::next“(调用"SkTSearch")位于符号表中。
参考资料:
被调用的函数"SkTSearch“位于SkTSearch.h中:
template <typename T, bool (LESS)(const T&, const T&)> struct SkTLessFunctionToFunctorAdaptor {
bool operator()(const T& a, const T& b) { return LESS(a, b); }
};
// Specialization for case when T==K and the caller wants to use a function rather than functor.
template <typename T, bool (LESS)(const T&, const T&)>
int SkTSearch(const T base[], int count, const T& target, size_t elemSize) {
static SkTLessFunctionToFunctorAdaptor<T, LESS> functor;
return SkTSearch(base, count, target, elemSize, functor);
}发布于 2020-03-28 04:57:02
(非显式-专门化)模板实体必须在每个使用实体的翻译单元中有一个定义,以便需要定义。唯一的例外是,如果实体在某个翻译单元中显式实例化。
因此,如果编译器可以内联转换单元中的所有调用(或者没有调用),编译器就不需要发出模板类的成员函数或函数模板的定义,因为编译器知道其他翻译单元也有可用的定义(如果它们需要的话)。如果所有调用都是内联的,也不需要发出未定义的符号,因为没有剩下的调用需要由链接器解决。
上述规则是为什么,如果不使用显式实例化/专门化,通常必须在头文件而不是源文件中定义模板和类模板的成员。
https://stackoverflow.com/questions/60897142
复制相似问题