内联函数
本帖最后由 zhaoomeng 于 2012-12-06 20:09:38 编辑 请看以下4个程序
(1)inline void facts(){}
int main()
{
void facts();
facts();
}
(2)inline void facts(){}
void facts();
int main()
{
facts();
}
(3)void facts();
int main()
{
facts();
}
inline void facts(){}
(4) int main()
{
void facts();
facts();
}
inline void facts(){}
其中为什么唯独(4)出错呢?
错误信息如下: error LNK2019: 无法解析的外部符号 "void __cdecl facts(void)" (?facts@@YAXXZ),该符号在函数 _main 中被引用(VS2012)
我知道内联函数应当定义于头文件的规定,我只是很想知道(4)不合法的原因?
[解决办法]
这是 declaration scope, unqualified name lookup, 以及 inline function definition 联合作用的结果。
具体到 (4) 的情况,void facts (); 出现在 main 函数里面,因此这个 facts 只具有 block scope,用人的话说这个 facts 就是 main-facts, 而非 ::facts,因此在 (4) 里面 facts 的调用点执行 unqualified name lookup 的结果是找到了 main-facts,而不是 ::facts,后者还不存在呢。后面 inline facts 定义的时候,facts 才出现为 global namespace scope,不过标准没要求 inline function 的定义一定存在,3.2/3 说
An inline function shall be defined in every translation unit in which it is odr-used.
这句话只说 odr-used inline function 一定要有定义,没说没用到的是否要有定义,因此编译器可以自由发挥了。
关键是这里的 inline function 没用被 odr-used,因为调用点的 facts 被决议为 main-facts,而非 ::facts,即编译器不认为 main-facts 和 ::facts 是一个东西。因此从编译器的角度讲,::facts 根本就没有用到(odr-used),所以也不需要有定义,因此 inline facts 压根就没产生对应的代码。然后编译器的事儿完了,链接器接手,结果这回郁闷了,因为调用点说我需要跳转到一个叫 facts 的函数,但是 linker 发现这函数压根就不存在(因为inline定义没有生成代码),所以 linker 就报错。
(3) 是正确的,因为调用点的 facts 决议为 ::facts,因此编译器知道后面的 inline function 在 main 里面调用了,所以是 odr-used 了,所以必须生成代码,因此木有问题了。
(4) 改成这样也没有问题
int main()
{
void facts();
facts();
}
void facts(){}
int main()
{
void facts();
facts();
}
namespace mangle
{
void facts(){}
}
using namespace mangle;
//仅供测试,不要在工程中只用这样的手法。
int main()
{
void facts();
//估计此处, 编译器可否inline,如何inline,所以多半没有inline
facts();
return 0;
}
inline void facts(){}
//防止编译器在obj中删除inline函数facts
void dummy(void (* &pf)())
{
pf = &facts;
}