编译器是否对字符串的生成进行了优化?

4

我正在尝试回答另一个关于==操作符的问题,我创建了这段代码:

NSString *aString = @"Hello";
NSString *bString = aString;
NSString *cString = @"Hello";

if (aString == bString)
    NSLog(@"CHECK 1");

if (bString == cString)
    NSLog(@"CHECK 2");

if ([aString isEqual:bString])
    NSLog(@"CHECK 3");

if ([aString isEqual:cString])
    NSLog(@"CHECK 4");

NSLog(@"%i", aString);
NSLog(@"%i", bString);
NSLog(@"%i", cString);

但是结果让我感到惊讶:

Equal[6599:10b] CHECK 1
Equal[6599:10b] CHECK 2
Equal[6599:10b] CHECK 3
Equal[6599:10b] CHECK 4
Equal[6599:10b] 8240
Equal[6599:10b] 8240
Equal[6599:10b] 8240

这里是否有一些编译器的技巧?
4个回答

6
显然在单个编译单元内进行了字符串去重。我建议您浏览一下man gcc,并访问所有使用“string”的选项。您会发现一些直接与字面值NSString及其免费桥接的对应项CFString有关的选项:
  • -fconstant-string-class=class-name设置用于实例化@"..."字面量的类的名称。它默认为NSConstantString,除非您使用GNU运行时。 (如果您不知道自己是否在使用,则不是。)
  • -fconstant-cfstrings启用内置函数来创建CFString,当您编写CFSTR(...)时。

您可以使用-fwritable-strings禁用C字符串字面量的去重,但此选项已被弃用。我无法想出一种组合选项,以停止在Objective-C文件中对NSString字面量进行去重。(有人想谈谈Pascal字符串字面量吗?)

您可以看到-fconstant-cfstringsCFString.h中发挥作用,定义了CFSTR()宏,用于创建CFString字面量:

    #ifdef __CONSTANT_CFSTRINGS__
    #define CFSTR(cStr)  ((CFStringRef) __builtin___CFStringMakeConstantString ("" cStr ""))
    #else
    #define CFSTR(cStr)  __CFStringMakeConstantString("" cStr "")
    #endif

如果你查看非内置函数__CFStringMakeConstantString()CFString.c的实现,你会发现该函数确实使用一个非常大的CFMutableDictionary来执行唯一化:

    if ((result = (CFStringRef)CFDictionaryGetValue(constantStringTable, cStr))) {
        __CFSpinUnlock(&_CFSTRLock);
    }
    // . . .
    return result;

请参见对问题的回答:“什么是字符串常量和字符串字面值之间的区别?”


4

NSString被定义为不可变类型,因此每当编译器可以通过合并相同的字符串来优化代码时,它都应该这样做。正如您的代码所示,gcc显然确实对简单情况进行了此优化。


这是正确的。字符串的内部类型实际上是NSConstantString,它不能被释放。编译器将其静态化,并覆盖了-release方法以使其无操作。 - Dave DeLong

2

对于cString和aString,C、C++和Objective C编译器可以重复使用编译时的字符串对象,如果该对象在多个位置声明。


0

也许是简单的写时复制优化?由于所有三个字符串都指向相同的“字符集”,因此在修改其中一个字符串之前,没有必要创建单独的副本。

可能字符存储在内存的静态部分(与代码一起),并且NSStrings*指向该内存部分。一旦尝试修改其中一个字符串,它将在其他地方(堆)创建新的字符串,然后引用该内存。


没错,我更多地是从概念上考虑。无论如何,它们似乎都指向同一部分内存,因为它们表示相同的字符组。 - stefanB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接