【问题标题】:Is string formation optimized by the compiler?编译器是否优化了字符串格式?
【发布时间】:2010-11-22 03:40:29
【问题描述】:

我试图回答关于 == 运算符的另一个问题,我创建了以下代码:

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

这里有一些编译器诡计吗?

【问题讨论】:

    标签: objective-c cocoa compiler-construction


    【解决方案1】:

    至少在单个编译单元中,显然存在字符串唯一性。我建议您通过man gcc 进行一次简短的浏览,在此期间您可以访问“字符串”的所有用法。您会发现一些与文字 NSStrings 及其免费桥接对应物 CFStrings 直接相关的选项:

    • -fconstant-string-class=class-name 设置用于实例化 @"..." 文字的类的名称。它默认为NSConstantString,除非您使用的是 GNU 运行时。 (如果你不知道自己是不是,那你就不是。)
    • -fconstant-cfstrings 允许使用内置函数在您编写 CFSTR(...) 时创建 CFStrings。

    您可以使用 -fwritable-strings 禁用 C 字符串文字的唯一性,但不推荐使用此选项。我想不出一个组合选项来阻止 NSString 在 Objective-C 文件中的文字的唯一性。 (有人想和 Pascal 字符串文字对话吗?)

    您会看到 -fconstant-cfstringsCFString.h 用于创建 CFString 文字的 CFSTR() 宏的定义中发挥作用:

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

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

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

    另请参阅对问题的回复,"What's the difference between a string constant and a string literal?"

    【讨论】:

      【解决方案2】:

      NSString 被定义为不可变类型,因此只要编译器可以通过组合相同的字符串来优化事物,它就应该这样做。正如您的代码所演示的,gcc 显然确实为简单的情况执行了这种优化。

      【讨论】:

      • 这是正确的。字符串的内部类型实际上是一个 NSConstantString,不能被释放。编译器将其设为静态显然将其 -release 方法覆盖为无操作。
      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

        • 没错,我是在概念上思考...无论如何,它们似乎都指向内存的同一部分,因为它们代表同一组字符...
        猜你喜欢
        • 2011-05-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-20
        • 1970-01-01
        • 2018-07-24
        • 2014-05-23
        相关资源
        最近更新 更多