为什么在内联函数中调用的函数不需要定义?

发布于 2025-01-22 18:46:05 字数 1725 浏览 1 评论 0原文

考虑以下示例:

extern void not_defined();

void f() {
    not_defined();
}

int main() {}

如果我要编译并链接上述程序,则会获得链接器错误undefined引用到not_defined()https://godbolt.org/z/jpzsck7ja

( 代码> not_defined 。

但是,如果我制作f() inline函数,则程序正确编译和链接( https://godbolt.org/z/qeeob9ann ):

extern void not_defined();

// inline is added here
inline void f() {
    not_defined();
}

int main() {}

这也适用于成员函数的内联定义(因为它们也是内联的?) xce3neofw“ rel =” nofollow noreferrer”> https://godbolt.org/z/xce3neofw

extern void not_defined();

struct C {
    void f_member() { 
        not_defined(); 
    }
    
    void recurse() { 
        f_member(); 
    };
};

inline void f_free_inline() {
    not_defined();
}

// void f_free() {
//     not_defined();
// }

int main() {
    C c;
    // f_free_inline();
}

)在main()中,它不再有效。由于recurse调用f_memberf_member调用not_defined()

所以我的问题是,导致这可能的内联函数有什么特别之处?

编辑:

如果内联函数在模块的范围内(即使未导出),则此技巧停止工作:

export module mod_interface;

extern void not_defined();

export inline void f_module() {
  not_defined();
}

以上会导致not_defined 。

这很可悲,因为我正在将图书馆移植到模块上,并突然得到了很多不确定的参考文献。其中一些功能包裹在内联函数中。

Consider the following example:

extern void not_defined();

void f() {
    not_defined();
}

int main() {}

If I were to compile and link the above program, I get a linker error undefined reference to not_defined(). (https://godbolt.org/z/jPzscK7ja)

This is expected because I am ODR using not_defined.

However, if I make f() a inline function, the program compiles and links correctly (https://godbolt.org/z/qEEob9ann):

extern void not_defined();

// inline is added here
inline void f() {
    not_defined();
}

int main() {}

This also works for inline definitions of member functions (since they are also inline?) (https://godbolt.org/z/xce3neofW):

extern void not_defined();

struct C {
    void f_member() { 
        not_defined(); 
    }
    
    void recurse() { 
        f_member(); 
    };
};

inline void f_free_inline() {
    not_defined();
}

// void f_free() {
//     not_defined();
// }

int main() {
    C c;
    // f_free_inline();
}

If I were to uncomment f_free or f_free_inline() in main() it no longer works . This effects seem to be even transitive, since recurse calls f_member, and f_member calls not_defined().

So my questions is, what's special about inline functions that makes this possible?

EDIT:

This trick cease to work if the inline function is inside the purview of a module (even if it is not exported):

export module mod_interface;

extern void not_defined();

export inline void f_module() {
  not_defined();
}

The above would result in a linker error for not_defined.

This is sad because I am porting a library to modules and suddenly got a lot of undefined references. Some of those functions in it were wrapped inside inline functions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

弥繁 2025-01-29 18:46:05

标准不仅是编译器行为的设定要求。这也是对程序员行为的一系列要求。

GCC的链接器如果函数x() odr使用了丢失的符号yinlinestatic代码>函数,因为如果它具有本地链接并且可以忽略不计,则不可能从外部模块中调用它们。

但是瞧!忽略了您能够编译和运行此程序的事实,根据标准,您的程序形成不佳。只有在Inline函数x()链接器中,只要在任何编译单元中找到对Inline X()的引用后,链接器才能将其优化。

如果不是内联功能,它将一直持续到链接的最后阶段,而丢失的名称将通过模块查找。编译器的实现使其在排除未使用x()之前将进行搜索。其他一些编译器的行为可能会有所不同。

这就是为什么它是“不良”代码,但“不需要诊断”。通过某些实现,可以进行诊断。有些实现将诊断出这两种情况是错误,而有些则无法检测到您的欺骗。某些实现只有在您拥有多个编译单元时才能检测到问题。

Standard is not only a set requirements for compiler behaviour. It's also a set of requirements to programmer's behaviour.

GCC's linker wouldn't complain if a function X() that ODR-used a missing symbol Y is inline or static function, as there is no possibility that they would be called from outside module if it has local linkage and negligible, if it was inline.

But lo! Disregard the fact that you're able to compile and run this program, your program is ill-formed according to standard. Only in case of inline function X() linker would optimize it out as soon as it didn't found a reference to inline X() in any of compile units.

If it's not inline function, it would stay until final stage of linking and the missing name will be looked up through modules. Implementation of your compiler is such that it would be searched for before excluding unused X(). Some other compiler may behave differently.

That's why it's "ill-formed" code, but "no diagnostic required". Diagnostic is possible with certain implementations. Some implementations will diagnose both cases as an error and some are unable to detect your deception. Some implementations will detect the problem only if you had more than one compile unit.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文