c++ 中的静态成员函数复制到多个翻译单元?
我的程序中有一个辅助类,其中有许多静态函数在我的程序的不同类中使用。例如
helper.h
:
Class helper {
public:
static void fn1 ()
{ /* defined in header itself */ }
/* fn2 defined in src file helper.cpp */
static void fn2();
}
Helper 仅具有静态成员函数。因此,其他模块不会创建 helper 对象。辅助函数在其他模块中使用,例如:
A.cpp
#include "helper.h"
A::foo() {
helper::fn1();
helper::fn2();
}
B.cpp
#include "helper.h"
B::foo() {
helper::fn1();
helper::fn2();
}
编译器是否在 A.cpp
和 A.cpp
中创建辅助函数的单独副本B.cpp
?我读了一些早期的帖子,并从编译器将创建的回复中收集到了这一点。但是当我将 fn1
和 fn2
的地址打印为 printf("Address of fn1 is %p\n", &helper::fn1);< /code> 和
printf("Address of fn1 is %p\n", &helper::fn1);
来自 A.cpp
和 B。 cpp
,我得到相同的地址。我现在很困惑。有人可以澄清一下,如果我遗漏了什么。
我担心辅助函数的多个副本(如果发生)的原因是我们正在尝试减少可执行文件的大小并希望对其进行优化。
I have a helper class in my program which has many static functions used in different classes of my program. E.g.
helper.h
:
Class helper {
public:
static void fn1 ()
{ /* defined in header itself */ }
/* fn2 defined in src file helper.cpp */
static void fn2();
}
Helper has only static member functions. So, no objects of helper are created by other modules. Helper functions are used in other modules like:
A.cpp
#include "helper.h"
A::foo() {
helper::fn1();
helper::fn2();
}
B.cpp
#include "helper.h"
B::foo() {
helper::fn1();
helper::fn2();
}
Does the compiler create separate copies of helper functions in A.cpp
and B.cpp
? I read some earlier posts and I gathered from the replies that compiler will create so. But when I print the address of fn1
and fn2
as printf("Address of fn1 is %p\n", &helper::fn1);
and printf("Address of fn1 is %p\n", &helper::fn1);
from both A.cpp
and B.cpp
, I get the same address. I'm confused now. Can someone clarify, If I'm missing something.
The reason I'm worried about multiple copies of helper functions (if it happens) is we are trying to reduce our executable size and wanted to optimize it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
类体内定义的函数被隐式标记为
inline
。如果您获取函数的地址,编译器还将创建该函数的常规副本(每个编译单元),但链接器将仅选择这些副本之一以包含在可执行文件中,因此只有一个地址。但是,内联过程可能会复制该函数的许多副本,甚至多于编译单元的数量。通常,复制代码所增加的大小会被通过消除参数传递和函数调用开销以及消除公共子表达式的机会等而可能增加的优化所抵消。尽管内联通常被认为是大小和速度之间的权衡,但大小会增加通常可以忽略不计,甚至为负值。
刚刚在类中声明然后在单个编译单元中实现的函数在可执行文件中肯定只有一份副本。
Functions defined inside the class body are implicitly marked
inline
. If you take the address of the function, the compiler will also create a regular copy of the function (per compilation unit), but the linker will pick just one of these copies to include in the executable, so there's only one address.However, the inlining process could make many copies of the function, even more than the number of compilation units. Often the increased size of duplicating the code is offset by the increased optimization possible by eliminating argument passing and function call overhead, as well as opportunities for common subexpression elimination, etc. Although inlining is often considered a tradeoff between size and speed, the size increase is often negligible or even negative.
The function that's just declared in the class and then implemented in a single compilation unit, definitely has just one copy in the executable.
如果可见(例如,在类声明中定义),则它被许多编译器隐式声明为内联。
如果内联,那么是的,在某些情况下它可能被复制,在某些情况下内联,在其他情况下部分内联。
它遵循单一定义规则(ODR),链接时在多个翻译中找到的副本将被删除(除非您启用了私有外部内联,否则您实际上可能会得到冗余的导出实现)。
如果您来自 C: static 在这种情况下不会创建该函数的唯一副本 - 它只是意味着您可以在没有声明它的类的实例的情况下调用该函数。
if visible (e.g., defined in the class declaration), then it's implicitly declared inline by many compilers.
if inlined, then yes it may be copied in some cases, inlined in some cases, and partially inlined in other cases.
it follows the One Definition Rule (ODR), copies found in multiple translations will be removed when linked (unless you have enabled private extern inlines, then you could really end up with redundant exported implementations).
if you are coming from C: static does not create a unique copy of the function in this case -- it just means that you may call the function without an instance of the class which declares it.
内联静态类方法与内联自由函数没有太大区别。理论上,ODR 规则意味着该函数只有一个实例,但实际上编译器可能始终内联它,因此实际上不存在该函数本身的实例。
然而,获取函数地址这一行为将迫使编译器创建该函数的实例,而执行 ODR 和执行 ODR 则是编译系统的问题。因此请确保您始终获得相同的地址。
An inlined static class method is not that different from an inlined free function. Theoretically the ODR rule means that there is a single instance of the function, but in practice the compiler may have always inlined it so that there is in fact no instance of the function per se.
However, the very act of taking the address of the function will force the compiler to create an instance of the function, and it is the compilation system's problem to enforce the ODR and hence ensure that you always get the same address.