在C ++中删除未使用(未引用)的静态全局变量常量

时间:2010-04-17 14:55:36

标签: c++

更新

我尝试删除静态修饰符,并尝试将它们放在命名空间(以及两者中),但没有一个工作。


您好,

我有一个头文件,其中包含常见的常量,例如名称和东西,这些常量会自动包含在每个项目中(下面是一个示例)。问题是它们是否包含在已编译的二进制文件(EXE)中,无论它们是否被使用(引用)。如果我改用DEFINE,那么如果没有使用它们,它们就不会被包括在内,但当然consts比定义更好......我尝试使用Google搜索,但我能找到的最接近的是a question就在这里SO这没有太大帮助。除了i18n之外,如何保留那些未使用的二进制文件,同时仍然保持这样的易用性?

感谢。


//COMMON.H:
  static const CString s_Company _T("Acme inc.");
  //etc. others
  static const CString s_Digits  _T("0123456789");

//TEST.CPP:
  #include common.h
  int main() {
    AfxMessageBox(s_Company);
  }

  //s_Company should be in the final EXE, but s_Digits should not be, but is

4 个答案:

答案 0 :(得分:2)

它们未从二进制文件中删除的原因是因为它们 使用:CString不是POD类型,因此当您在全局范围内创建它们的实例时,编译器必须生成代码来调用它们的构造函数和析构函数。

如果您希望剥离未使用的符号,只需将CString替换为POD类型,例如const TCHAR*

static const TCHAR *s_Company = _T("Acme inc.");
static const TCHAR *s_Digits  = _T("0123456789");

然后,编译器会自动从二进制文件中删除未使用的常量。但是,要记住的一件重要事情是,如果您的字符串在多个文件中使用,那么您的二进制文件中将包含这些字符串的多个副本,每个翻译单元使用该字符串一个副本。甚至没有gcc的-fmerge-constants选项似乎解决了这个问题。如果您不希望发生这种情况,则需要在头文件中使用extern声明,然后将字符串常量值放在源文件中(通常在一个文件中,但这不是必需的)。这也允许您更改常量,而无需重新编译使用它们的每个文件。

答案 1 :(得分:1)

如果您不需要将值作为文字,则可以在头文件中将它们声明为:

extern const CString s_Company;

将它们中的每一个放在它自己的源文件中,将其定义为:

const CString s_Company _T("Acme inc.");

然后你只能链接你需要的常数;链接器会在错误消息中告诉您是否遗漏了! (还有一些方法可以告诉编译器不要在构建的库中公开这些符号 - 假设你正在构建一个库 - 但它们不是标准的或可移植的。)

答案 2 :(得分:0)

如果定义明确的规则,以便在您想要使用什么时明确,那么您可以使用这样的预处理器定义:

#if defined CONFIG_COMPANY
  static const CString s_Company _T("Acme inc.");
#elif defined CONFIG_DIGITS
  static const CString s_Digits  _T("0123456789");
#endif

然后,您可以在单独的配置标头中定义或不定义这些值中的任何一个。

顺便说一下,如果要将此文件包含在许多源文件中,那么您应该避免将这些常量声明为static。它们具有内部链接,您将在所有翻译单元中单独复制它们。

答案 3 :(得分:0)

在Windows上,特别是使用MFC,答案是将字符串放入资源,并使用LoadResource / LoadString从那里加载字符串(参见http://msdn.microsoft.com/en-us/library/a44fb3wy(VS.80).aspx

在您的情况下,您有两个不变的CStrings,因此资源编译器将生成类似

的内容
#define IDS_COMPANY 1
#define IDS_DIGITS  2

所以在这种情况下你会得到一个带有两个字符串的.dll。你的app会加载.dll(AfxLoadLibrary)。然后,当您需要字符串时,您的应用程序会从资源.dll加载它。

这使得Windows应用程序不会因全局静态字符串,位图等而膨胀。