【问题标题】:How to use typed constants with "unused variable" warnings?如何使用带有“未使用变量”警告的类型常量?
【发布时间】:2013-02-18 23:34:57
【问题描述】:

我使用的是 Xcode 4.6,并且我有一个头文件,其中包含我在整个代码中使用的一些常量。我不想使用预处理器指令,因为我希望它们被正确输入等等。

例如,我的一个 .h 文件中有此代码:

static NSString *kErrorCannotDivideByZero = @"Error: Cannot divide by zero";

我在相应的 .m 文件中使用它:

[self showToast:kErrorCannotDivideByZero];

我收到警告:

/path/to/my/headerFile.h:32:18: Unused variable 'kErrorCannotDivideByZero'

我知道这只是一个警告,但其中大约 50 个警告阻塞了我的编译器输出。

为什么我会收到此警告以及如何正确解决?

我对简单地禁止所有未使用的变量警告不感兴趣,因为我确实想要获得合法的警告。

【问题讨论】:

  • 您确定在 HEADER 文件中而不是在 .m 文件中包含静态 NSString(并且在标头中只有一个 extern static NSString)不是您的问题的原因吗?我怀疑每次将其包含到 .m 文件中时都会生成一个不同的静态实例。
  • 我想要一些可以在整个应用程序中使用的可重用字符串。你有什么建议?
  • 正如 Josh 下面所说,“extern NSString *foo;”在标头中,然后在 .m 中声明真正的非静态实例 ONCE。或者只是#define FOO @"StringLiteral"
  • 正如我所说,我想避免使用预处理器。回复:在 .h 文件中定义变量,然后在 .m 文件中将它们声明为真实变量:如果我想在我的应用程序的其他部分中使用该变量,我是否必须在每个部分中一遍又一遍地声明它文件?自 90 年代上大学以来,我就没有深入研究过真正的 C 代码。
  • OI。标题中的外部。非外部一次在.m。完毕。你无法避免预处理器。 #define 和 #import 和 #include 都使用它。学会爱它。

标签: objective-c c xcode


【解决方案1】:

在标题中声明 extern 而不是 static。您正在做的是为包含您的标题的每个翻译单元创建一个变量,这就是 Clang 警告您的原因,因为它是合法的未使用的已定义变量。 extern 关键字告诉编译器该变量的定义在其他地方找到(它可能在同一个翻译单元中,也可能在另一个翻译单元中)。

在你的标题中,有:

// declare that the constant exists somewhere
extern NSString * const kErrorCannotDivideByZero;

在您的 一个 .m 文件(通常与标题同名的文件)中,放入

// define the constant, i.e. this is where it exists
NSString * const kErrorCannotDivideByZero = @"Error: Cannot divide by zero";

声明变量extern 允许编译器确保您正确处理该变量,即使它不知道它是在哪里定义的(例如,您不能将它用作NSArray)。链接器的任务是确保您确实在某处定义了它。

【讨论】:

  • 如果 Foo.h 有 extern 并且 Foo.m 定义了它指向的内容... Bar.m #import Foo.h 并且能够使用 kErrorCannotDivideByZero 吗?
  • @KennyWyland:是的,绝对的。标头中的声明只是告诉编译器在某处存在名为kErrorCannotDivideByZeroNSString * 类型的对象。链接器(将所有已编译的源文件链接在一起)将解析对 one 定义的所有引用。
  • 只是为了扩展这个解决方案:我通常做的是在 MyIncludes.h 中声明我的外部变量。不需要是常量; extern NSString* EnglishHiddenKey; 会很好。现在我将 MyIncludes.h 导入到 .pch 文件中,这样每个人都可以全局看到它,并且我在 MyIncludes.m 中定义了我的外部,例如NSString* EnglishHiddenKey = @"englishHidden";
  • @matt:它不需要是const,但是将它设置为const 可以防止值在运行时发生变化。
【解决方案2】:

Clang 将允许您将警告标志推入和弹出“诊断”堆栈:"Controlling diagnostics via pragmas"。您可以像这样包装某些代码:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-variable"

static NSString *kErrorCannotDivideByZero = @"Error: Cannot divide by zero";

#pragma clang diagnostic pop

告诉 Clang 你知道这些没有被使用,在这个特定的例子中没关系。

顺便说一句,您可能不想在要导入到许多不同位置的文件中定义这些变量——这是导致关于变量重新定义的链接器错误的好方法(尽管这只会发生在该变量是全局链接的——声明/定义没有static)。像这样的常量的通常模式是在标题中放置extern 声明,并在另一个文件中定义变量。详情请见Referencing a static NSString * const from another class

正如dreamlax 所指出的,您实际上收到了这些警告,因为每个导入您的标头的文件都获得了自己的static 变量副本;当我建议上面的#pragma 技术时,我误解了你的要求。

【讨论】:

  • +1 表示答案的第二部分;这是正确的解决方案。
  • 不会有任何变量重定义错误,因为变量声明为static,所以它没有外部链接。
  • 哦,对了,每个导入头文件的文件都有自己的变量@dreamlax?
  • @JoshCaswell:确实,他们都有自己的同名副本。
【解决方案3】:

让你的常量const:

static NSString * const kErrorCannotDivideByZero = @"Error: Cannot divide by zero";

(正如其他人指出的那样,使用extern 并在实现文件中定义)

【讨论】:

  • +1:Apple 不仅在它们的标题中使用const,而且这也意味着你不能意外地重新分配kErrorCannotDivideByZero
  • 我的代码中最初有const,但是在将 NSStrings 传递给各种 api 时,我收到了很多关于类型不匹配的警告。
  • 当您声明为const NSString *(指向常量的指针)而不是NSString * const(常量指针)时,通常会发生这种情况
  • 感谢塞巴斯蒂安,这是我没有想到的差异。
【解决方案4】:

也许,与其将它们初始化为字符串文字,不如运行一个初始化函数,该函数从特定于语言环境的文件中加载这些值,以便错误出现在翻译的语言中。当您的初始化函数分配给该变量时,您的编译器可能会认为该变量需要存在才能使编译成功。

【讨论】:

  • 提供Localizable.strings 文件来翻译错误会更容易。
  • 假设 OP 不想要他/她也可以在他/她的 C 项目中使用的答案是愚蠢的,因为他/她也标记了“C”。
  • 我认为这根本不傻。 Objective-C 是 C 的超集,尽管提供的代码显然是 Objective-C,但他收到的警告是因为 Objective-C 源于 C。此外,即使对于 C 项目,也已经有本地化解决方案,例如GNU gettext.
  • 我想你误解了我最后的评论。请允许我重申一下:也许 OP 也使用 C 编程,并且想要一个也可以在 C 中工作的解决方案,而没有使用商业限制许可的第三方库的问题。
  • 这是一个基于 c 标签的关于未使用变量的 Objective-C 问题的大量假设。您的答案仍然不会产生影响,因为即使您从一个翻译单元中的外部文件加载字符串,您也不会在任何其他翻译单元中看到任何差异,因为该变量被声明为 static。因此,其他翻译单元不仅不会看到从外部加载字符串的任何影响,而且它们还将继续调用未使用变量警告。
【解决方案5】:

GCC(我假设是 clang)不会警告未使用的常量。这里要注意的一个陷阱是指针必须是 const 指针,而不仅仅是指向 const 的指针;因此,要正确声明一个不会触发任何警告的未使用字符串常量,您需要:

const char * const myConst = "myConst";

【讨论】:

    【解决方案6】:

    您可以将所有静态变量声明移动到您各自的 .m 文件中。这应该消除所有那些“未使用的变量”警告。原因是静态变量仅限于文件级范围。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多