字符串常量和字符串文字有什么区别?

What's the difference between a string constant and a string literal?

提问人:Benedict Cohen 提问时间:8/25/2008 最后编辑:R.. GitHub STOP HELPING ICEBenedict Cohen 更新时间:1/25/2016 访问量:40358

问:

我正在学习 objective-C 和 Cocoa,并遇到了以下陈述:

Cocoa 框架期望全局字符串常量而不是字符串文字用于字典键、通知和异常名称以及一些接受字符串的方法参数。

我只在高级语言中工作过,所以从来没有考虑过字符串的细节。字符串常量和字符串文字有什么区别?

objective-c 字符串

评论


答:

3赞 Brad Wilson 8/25/2008 #1

让我们使用 C++,因为我的目标 C 完全不存在。

如果将字符串存储到常量变量中:

const std::string mystring = "my string";

现在,当您调用方法时,您使用的是my_string,您使用的是字符串常量:

someMethod(mystring);

或者,您可以直接使用字符串文本调用这些方法:

someMethod("my string");

据推测,他们鼓励您使用字符串常量的原因是因为 Objective C 不进行“实习”;也就是说,当您在多个位置使用相同的字符串文本时,它实际上是指向字符串的单独副本的不同指针。

对于字典键,这会产生巨大的差异,因为如果我能看到两个指针指向同一事物,这比必须进行整个字符串比较以确保字符串具有相等的值要便宜得多。

编辑:Mike,在 C# 中,字符串是不可变的,具有相同值的文字字符串都指向相同的字符串值。我想对于其他具有不可变字符串的语言也是如此。在具有可变字符串的 Ruby 中,它们提供了一种新的数据类型:符号(“foo” 与 :foo,前者是可变字符串,后者是通常用于哈希键的不可变标识符)。

87赞 Chris Hanson 8/25/2008 #2

在 Objective-C 中,语法是 的不可变文本实例。它不会像 Mike 假设的那样从字符串文字生成常量字符串。@"foo"NSString

Objective-C 编译器通常在编译单元中执行内部文本字符串(也就是说,它们合并了同一文本字符串的多个用途),并且链接器可以在直接链接到单个二进制文件的编译单元之间执行额外的内部插入。(由于 Cocoa 区分可变字符串和不可变字符串,并且文字字符串也始终是不可变的,因此这既简单又安全。

另一方面,常量字符串通常使用如下语法进行声明和定义:

// MyExample.h - declaration, other code references this
extern NSString * const MyExampleNotification;

// MyExample.m - definition, compiled for other code to reference
NSString * const MyExampleNotification = @"MyExampleNotification";

此处语法练习的要点是,通过确保即使在同一地址空间中的多个框架(共享库)中也只有该字符串的一个实例在使用,可以有效地使用该字符串。(关键字的位置很重要;它保证指针本身是恒定的。const

虽然刻录内存并不像 25MHz 68030 工作站和 8MB RAM 那样重要,但比较字符串是否相等可能需要时间。确保大多数时间字符串相等也有助于指针相等。

例如,您想按名称订阅来自对象的通知。如果对名称使用非常量字符串,则在确定谁对通知感兴趣时,发布通知时可能会进行大量逐字节字符串比较。如果这些比较中的大多数都因为被比较的字符串具有相同的指针而短路,那将是一个巨大的胜利。NSNotificationCenter

评论

1赞 Josh Brown 3/26/2010
迈克是对的。摘自《Programming in Objective-C 2.0》一书 - “The string @”Programming in Objective-C is fun.\n“ 是一个常量字符串对象的示例。
6赞 Chris Hanson 3/30/2010
“Programming in Objective-C 2.0”不是语言参考;因此,引用它就好像是这样是不正确的。在 C 中,“foo”被称为字符串文字。通常,“常量”是指指针或变量,而不是文字;根据定义,文本是常量。
2赞 bentford 6/16/2011
灯泡亮了!!当您想要枚举的效率但又不想使用数字作为值时,常量字符串很有用。很棒的答案,非常有帮助!
12赞 Jano 9/8/2012 #3

一些定义

文字是一个值,根据定义它是不可变的。例如:
常量是只读变量或指针。例如:
字符串文字是类似 .编译器会将其替换为 的实例。
字符串常量是指向 的只读指针。例如:
10const int age = 10;@""NSStringNSStringNSString *const name = @"John";

最后一行的一些评论:

  • 这是一个常量指针,而不是一个常量对象12 不在乎是否用 限定对象。如果你想要一个不可变的对象,你必须在对象3 中编写这个不可变性。objc_sendMsgconst
  • 所有表达式确实是不可变的。它们在编译时被替换为 的实例 4,这是具有固定内存布局5 专用子类。这也解释了为什么在编译时6 是唯一可以初始化的对象。@""NSConstantStringNSStringNSString

常量字符串等价于 。在这里,语法和程序员的意图都是错误的:被忽略,并且实例()已经是不可变的。const NSString* name = @"John";NSString const* name= @"John";const <object>NSStringNSConstantString

1 关键字 const applies 适用于紧挨着其左边的任何内容。如果它的左边没有任何东西,它就适用于它右边的任何东西。

2 这是运行时用于在 Objective-C 中发送所有消息的函数,因此您可以使用它来更改对象的状态。

3 示例:in const NSMutableArray *array = [NSMutableArray new];[数组 removeAllObjects];const 不会阻止最后一条语句。

4 重写表达式的 LLVM 代码是 RewriteModernObjC::RewriteObjCStringLiteral in RewriteModernObjC.cpp

5 要查看 NSConstantString 定义,请在 Xcode 中单击 cmd+。

6 为其他类创建编译时常量很容易,但这需要编译器使用专门的子类。这将破坏与旧 Objective-C 版本的兼容性。


返回您的报价

Cocoa 框架期望全局字符串常量而不是 字符串文字用于字典键、通知和 异常名称,以及一些采用字符串的方法参数。你 应始终首选字符串常量而不是字符串文字,当您 有一个选择。通过使用字符串常量,您可以获得 编译器来检查拼写,从而避免运行时错误。

它说文字容易出错。但它并没有说它们也更慢。比较:

// string literal
[dic objectForKey:@"a"];

// string constant
NSString *const a = @"a";
[dic objectForKey:a];

在第二种情况下,我使用带有 const 指针的键,因此,我可以执行 .比较哈希的实现,然后运行C函数,因此它比直接比较指针慢。这就是为什么常量字符串更好的原因:它们比较速度更快,更不容易出错。[a isEqualToString:b](a==b)isEqualToString:strcmp

如果您还希望常量字符串是全局字符串,请按以下步骤操作:

// header
extern NSString *const name;
// implementation
NSString *const name = @"john";