什么时候使用的函数不会出现在目标文件符号中 table
When will used function not appear in object file symbol table
有时在翻译单元 (TU) 中一些明确调用的函数不在编译目标文件的符号 table 中(使用 nm -aC file.o)。可能是什么原因?
原因可能是:
(1)调用优化:不是下面例子,是debug版本,用-g编译。
(2) 调用被预处理并删除:不适用于下面的示例,调用周围没有#if
(3) 别名或预处理有别名:不是下面的例子,在skia分支下的AOSP源代码中搜索过,没有相关的#define/typedef
(4) 由于它是内联的,为了提高编译速度,它可能不会在调用它的每个 TU 中编译。
(4-1) 但即使它没有被编译,它至少会作为一个未定义的符号出现在目标文件中,以便稍后链接器找到,但在下面的示例中根本没有那个符号.
(4-2) 如果是这样,考虑到所有调用该函数的TU都是独立编译的,编译器如何决定何时编译内联函数?
其他可能的原因是什么?
一个例子是 AOSP10 中的 SkOTTable_name.cpp:
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")在符号 table.
中
参考:
调用函数"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);
}
(非显式专门化)模板化实体必须在每个以需要定义的方式使用该实体的翻译单元中有一个定义。唯一的例外是实体是否在某个翻译单元中显式实例化。
因此,如果编译器可以内联翻译单元中的所有调用(或者如果有 none), 因为编译器知道其他翻译单元在需要时也有可用的定义。如果所有调用都是内联的,则也不需要发出未定义的符号,因为没有剩余的调用需要链接器解析。
上面的规则就是为什么如果不使用显式instantiation/specialization,通常模板和class模板的成员必须在头文件而不是源文件中定义。
有时在翻译单元 (TU) 中一些明确调用的函数不在编译目标文件的符号 table 中(使用 nm -aC file.o)。可能是什么原因?
原因可能是:
(1)调用优化:不是下面例子,是debug版本,用-g编译。
(2) 调用被预处理并删除:不适用于下面的示例,调用周围没有#if
(3) 别名或预处理有别名:不是下面的例子,在skia分支下的AOSP源代码中搜索过,没有相关的#define/typedef
(4) 由于它是内联的,为了提高编译速度,它可能不会在调用它的每个 TU 中编译。
(4-1) 但即使它没有被编译,它至少会作为一个未定义的符号出现在目标文件中,以便稍后链接器找到,但在下面的示例中根本没有那个符号.
(4-2) 如果是这样,考虑到所有调用该函数的TU都是独立编译的,编译器如何决定何时编译内联函数?
其他可能的原因是什么?
一个例子是 AOSP10 中的 SkOTTable_name.cpp:
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")在符号 table.
中参考:
调用函数"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);
}
(非显式专门化)模板化实体必须在每个以需要定义的方式使用该实体的翻译单元中有一个定义。唯一的例外是实体是否在某个翻译单元中显式实例化。
因此,如果编译器可以内联翻译单元中的所有调用(或者如果有 none), 因为编译器知道其他翻译单元在需要时也有可用的定义。如果所有调用都是内联的,则也不需要发出未定义的符号,因为没有剩余的调用需要链接器解析。
上面的规则就是为什么如果不使用显式instantiation/specialization,通常模板和class模板的成员必须在头文件而不是源文件中定义。