3

我们尝试在二进制对象中嵌入 what 字符串,以便我们可以看到已部署的可执行文件或共享库的版本号。通常我们将标准 CVS Id 信息嵌入到这个 what 字符串中。例如,我们可能嵌入:

const char cvsid[] = "@(#)OUR_TEAM_staging_remap_$Revision: 1.30 $ $Name:  $";

在 C 代码中。

从人(1)什么:

what 实用程序在每个文件名中搜索出现的模式 @(#),SCCS get 命令(请参阅 sccs-get(1))替换了 @(#) ID 关键字,并打印出 ", >, NEWLINE、\ 或 NULL 字符。

该变量只有一个实例,并且从未被引用。有人建议这可能会被编译器优化掉。

多年来,我一直在 C 和 C++ 以及各种编译器中使用这种技术,但我还没有看到什么字符串被优化掉了。

任何人都知道为什么它们没有被优化掉?

4

6 回答 6

2

通常这不会发生,因为无关字符串的成本很低,并且在这种情况下很有用,除其他外(例如,存储一堆字符串资源,只有代码中实际引用的第一个资源)。

于 2009-01-27T17:36:29.723 回答
2

它们可能不会被优化掉,因为您的编译器知道这些字符串可以用于这些目的。

当然,编译器完全可以优化掉它,只要程序的行为,更确切地说是可观察的行为,没有改变。这意味着对 volatile 的写入和读取顺序,并且对库函数的调用不会改变。

通过在您的应用程序中优化这样的字符串,我想这种行为不会改变。但是编译器想要可用并且尽量不以用户的方式进行攻击。这就是为什么它们也包含有用的扩展。如果您想确保它不会偶尔被优化,也许可以查看编译器扩展。GCC 有一个unused属性,它不会对未使用的对象发出警告。也许那个或类似的东西可以帮助你变量没有被优化掉。

从语言的角度来看,虽然有一个实用程序可以强制编译器保留它。

编辑:这里有一篇关于该主题的 usenet 帖子,有有用的答案。

于 2009-01-27T17:41:57.497 回答
2

直到最近(我在 2005 年年中发现了这个问题),还可以使用:

static const char sccs[] = "@(#)%W% %E%";

或源代码中的类似内容,GCC 和大多数其他编译器不会对其进行优化。大约从那个时候开始发布 GCC(可能是 GCC 4.0.x,起源于 2005 年 4 月),这些常量字符串被排除在二进制文件之外。因此,我不得不四处修改我的源代码以使变量在外部可见。编译器不可能单独查看目标文件并得出未使用该字符串的结论,因为可以想象文件之外的某些内容可能会引用它。所以,我的文件现在包含:

#ifndef lint
extern const char jlss_id_filename_c[];
const char jlss_id_filename_c[] = "@(#)$Id$";
#endif /* lint */

好的——这是一个混合体;我确实使用 RCS 来存储源代码,但我仍然更喜欢what用于ident识别文件 - 再加上我自己的 hackedwhat可以做到这两点whatident再加上我自己的一些调整。但我在一些文件中都有声明 - 不是全部 - 以及所有文件中的定义。(在一些现在不记得的警告标志下,当变量在被声明之前被定义时,我收到了警告。可能是 GCC 中的一个更改解决了这个问题;我不确定了。)

当我创建一个新文件时,我的模板生成器将“filename_c”替换为正在生成的文件的适当名称。标题也类似——尽管标识字符串只嵌入一个文件中以避免多个定义。

我更喜欢带有静态常量的旧系统——但这已经为我工作了 3 年多。

于 2009-01-31T07:22:04.823 回答
2

(是的,我知道这个问题很久以前就被问过了。但是这种新的回答方式是可用的,所以....)

gcc(至少在 3.3 及以下版本中),现在有编译器指令__attribute__((unused))将变量标记为“已知它可能未被引用”以抑制警告,并将__attribute__((used))其标记为已使用(因此不是优化的候选对象),即使没有其他代码实际引用它。

所以这可能会为你做:

static const char what_ident[] __attribute__((used)) = "@(#) $Id$";

如果linker仍然优化它,那么您可能需要将它放在标记为保持的部分中,而不管链接时间引用如何。

static const char what_ident[] __attribute__((section("what"), used)) = "@(#) $Id$";

并添加 gcc 选项-Wl,-bkeepfile:file.o,这样链接器就不会抑制 file.c 输出中未引用的部分。

于 2015-08-03T23:16:29.763 回答
1

Microsoft 的 Visual C++ 2005 有一个链接器选项,它应该控制它对未使用数据 /OPT:UNREF的处理方式:强制链接器保留未使用的数据,/OPT:REF允许它删除它。

但是,在我的简单测试中,该选项对语句没有影响

static char VersionString[] = "HELLO_WORLD 2.0";

无论标志如何,该字符串都出现在发布和调试二进制文件中。

于 2009-01-27T18:12:16.640 回答
1

如果没有“static”关键字,变量就不能被优化掉,因为另一个模块可能会声明一个对它的引用(使用 extern)。由于 C/C++ 通常一次编译一个文件,因此编译器无法知道是否存在外部引用。

通过添加 static 关键字,您可以告诉编译器该名称仅在编译中可见,使用和优化它成为可能。

我认为如果对象格式允许,链接器可以检测到未使用的全局变量并对其进行优化,尽管我不确定是否有人这样做。

于 2009-07-21T22:30:39.590 回答