关于C#:字符串常量和字符串文字之间有什么区别?

关于C#:字符串常量和字符串文字之间有什么区别?

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

我正在学习Objective-C和Cocoa,并且遇到了以下说法:

The Cocoa frameworks expect that global string constants rather than string literals are used for dictionary keys, notification and exception names, and some method parameters that take strings.

我只使用高级语言工作,因此不必过多考虑字符串的细节。 字符串常量和字符串文字有什么区别?


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

Objective-C编译器通常在编译单元中执行内部文字字符串,也就是说,它们合并了同一文字字符串的多种用法,而且链接程序有可能在直接链接到单个二进制文件的编译单元中进行其他实习。 (由于Cocoa区分可变字符串和不可变字符串,并且文字字符串也始终是不可变的,所以这可以简单明了且安全。)

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

1
2
3
4
5
// 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可能会进行大量的逐字节字符串比较。如果大多数比较由于所比较的字符串具有相同的指针而短路,那么这将是一个巨大的胜利。


一些定义

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

最后一行的一些评论:

  • 那是一个常量指针,而不是常量object1。 objc_sendMsg 2不在乎是否用const限定对象。如果您想要一个不可变的对象,则必须在对象3内对该不可变性进行编码。
  • 所有@""表达式的确是不可变的。它们在编译时被NSConstantString实例替换,这是NSString的专用子类,具有固定的内存布局。这也解释了为什么NSString是唯一可以在编译时初始化的对象6。

常量字符串为const NSString* name = @"John";,它等效于NSString const* name= @"John";。此处,语法和程序员意图都是错误的:const 被忽略,并且NSString实例(NSConstantString)已经不可变。

1关键字const适用于紧靠其左侧的任何内容。如果左侧没有任何内容,则适用于右侧的任何内容。

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

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

4重写表达式的LLVM代码在RewriteModernObjC.cpp中为RewriteModernObjC::RewriteObjCStringLiteral

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

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

返回您的报价

The Cocoa frameworks expect that global string constants rather than
string literals are used for dictionary keys, notification and
exception names, and some method parameters that take strings. You
should always prefer string constants over string literals when you
have a choice. By using string constants, you enlist the help of the
compiler to check your spelling and thus avoid runtime errors.

它说文字容易出错。但这并不表示它们也较慢。相比:

1
2
3
4
5
6
// string literal
[dic objectForKey:@"a"];

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

在第二种情况下,我使用带有const指针的键,因此可以代替[a isEqualToString:b]isEqualToString:的实现比较散列,然后运行C函数strcmp,因此它比直接比较指针要慢。这就是为什么常量字符串更好的原因:它们比较起来更快,并且不易出错。

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

1
2
3
4
// header
extern NSString *const name;
// implementation
NSString *const name = @"john";

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

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

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

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

1
someMethod(mystring);

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

1
someMethod("my string");

可能是因为它们鼓励您使用字符串常量,原因是因为Objective C不会进行" interning";也就是说,当您在多个地方使用相同的字符串文字时,实际上是指向该字符串的单独副本的不同指针。

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

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


推荐阅读