任何人都可以链接到 C++ 标准关于编译器删除全局和静态符号的内容?我以为您不能保证如果未引用全局符号,编译器将删除它们。我的一位同事断言,如果您的全局符号包含在主翻译单元中,即使未引用这些符号,也不会删除它们。
3 回答
有趣的是,我在 C++2003 标准中能找到的只是:
3.7.1 静态存储时长[basic.stc.static]
所有既不具有动态存储持续时间也不是本地对象的对象具有静态存储持续时间。这些对象的存储应持续到程序的持续时间(3.6.2、3.6.3)。
如果静态存储持续时间的对象具有初始化或具有副作用的析构函数,则即使它看起来未使用,也不应将其消除,除非可以按照 12.8 中的规定消除类对象或其副本。
这意味着该标准允许在静态存储中删除项目,如果它们的初始化和销毁没有副作用并且它们未被使用。
如果有更直接的许可,我没有看到(但也许其他人会看到)。
但是,应该注意的是,让链接器消除最终图像中未使用的对象是一种非常常见的优化。
你问的是关于链接的问题,尽管 C++ 标准说链接应该作为翻译的最后阶段发生,但它没有说明应该如何发生。例如,它说函数引用被解析,但它不要求它们按名称解析,并且它没有说明解析后引用会发生什么。
要确定编译器在目标代码中包含哪些符号,以及链接器删除或不删除哪些符号,您需要分别查阅您正在使用的编译器和链接器的文档。
我相信这是这种方式(我们之前在评论线程中就堆栈溢出进行了长时间的讨论):
- 如果具有命名空间范围的对象(即具有静态存储持续时间的对象)的初始化或析构函数没有副作用,则如果在其翻译单元中没有使用函数或对象,则可以优化该对象。
- 对于初始化或销毁导致副作用的对象,编译器可能不会优化该变量,即使没有使用其翻译单元的对象或函数。
在任何情况下,编译器都必须在使用完成之前初始化对象,但不一定在 main 之前。我做了测试,因为 stackoverflow 的某个人说如果没有这样的用途,gcc 可以有效地优化具有副作用的对象的初始化。我现在测试了,我已经看到 gcc 没有这样做。此外,据我了解标准,无论如何都不允许这样做。
如果您只获取要初始化的对象的翻译单元的对象或函数的地址就足够了。为了安全起见,最好始终这样做,即使对于具有副作用的初始化对象也是如此。假设您的朋友是对的,我认为对于 main 的翻译单元,main
总是被视为正在使用,因此该条件立即得到满足。规则可以在3.6.2p3
,3.7.1p2
和3.2p2
(使用的定义), 1.9p7
(副作用的定义)中找到。