В чем разница между Строковой константой и строковым литералом?


Я изучаю objective-C и Cocoa и наткнулся на это утверждение:

рамки Cocoa ожидают, что глобальные строковые константы, а не строковые литералы используются для ключей словаря, имен уведомлений и исключений, а также некоторых параметров метода, которые принимают строки.

Я работал только на языках более высокого уровня, поэтому никогда не приходилось рассматривать детали строк так много. В чем разница между Строковой константой и строкой буквально?

3 58

3 ответа:

в Objective-C, синтаксис @"foo" это неизменяемые,литерал экземпляр NSString. Он не делает постоянную строку из строкового литерала, как предполагает Майк.

компиляторы Objective-C обычно do интернировать литеральные строки в единицах компиляции - то есть они объединяют многократное использование одной и той же литеральной строки - и компоновщик может выполнять дополнительную интернирование между единицами компиляции, которые непосредственно связаны в один двоичный файл. (Поскольку 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 с 8 МБ оперативной памяти, сравнение строк для равенства может занять некоторое время. Гарантируя, что большая часть строк времени, которые равны, также будут равны указателю помогает.

скажем, например, вы хотите подписаться на уведомления от объекта по имени. Если вы используете непостоянные строки для имен, то NSNotificationCenter публикация уведомления может привести к тому, что будет сделано много байтовых сравнений строк при определении того, кто в этом заинтересован. Если большинство из этих сравнений закорочены, потому что сравниваемые строки имеют один и тот же указатель, это может быть большой выигрыш.

некоторые определения

A литерал - это значение, которое является неизменным по определению. например: 10
А постоянный-это переменная или указатель только для чтения. например: const int age = 10;
А строковый литерал - это выражение, как @"". Компилятор заменит это экземпляром NSString.
А строковая константа - это указатель только для чтения на NSString. например: NSString *const name = @"John";

некоторые комментарии к последнему линия:

  • это постоянный указатель, а не постоянный объект1. objc_sendMsg2 не волнует, если вы квалифицируете объекта с const. Если вам нужен неизменяемый объект, вы должны закодировать эту неизменность внутри объекта3.
  • все @"" выражения действительно являются неизменными. Они заменяются4 во время компиляции с экземплярами NSConstantString, который является специализированным подклассом NSString с фиксированным расположение памяти5. Это также объясняет, почему NSString - это единственный объект, который может быть инициализирован во время компиляции6.

A постоянная строка будет const NSString* name = @"John"; что эквивалентно NSString const* name= @"John";. Здесь и синтаксис, и намерение программиста неверны:const <object> игнорируется, а то NSString экземпляр (NSConstantString) был уже неизменным.

1 ключевое слово const применяется относится к тому, что есть сразу же налево. Если слева от него ничего нет, то это относится ко всему, что находится непосредственно справа от него.

2 это функция, которую среда выполнения использует для отправки всех сообщений в Objective-C, и поэтому то, что вы можете использовать для изменения состояния объекта.

3 пример: in const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects]; const не предотвращает последнее утверждение.

4 в LLVM код, который переписывает выражение RewriteModernObjC::RewriteObjCStringLiteral в RewriteModernObjC.СРР.

5 посмотреть NSConstantString определение, cmd + щелкните его в Xcode.

6 создание констант времени компиляции для других классов было бы легко, но это потребует от компилятора использовать специализированный подкласс. Это нарушило бы совместимость со старым Objective-C версии.


вернемся к вашей цитате

рамки Cocoa ожидают, что глобальные строковые константы, а не строковые литералы используются для ключей словаря, уведомлений и имена исключений, и некоторые параметры метода, которые принимают строки. Вы всегда следует предпочитать строковые константы строковым литералам, когда вы иметь выбор. С помощью строковых констант можно заручиться помощью компилятор для проверки орфографии и таким образом избежать ошибок во время выполнения.

он говорит, что литералы ошибок. Но это не говорит о том, что они также медленнее. Сравните:

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

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

во втором случае я использую ключи с указателями const, поэтому вместо [a isEqualToString:b], я могу (a==b). Реализация isEqualToString: сравнивает хэш и затем запускает функцию C strcmp, так что это медленнее, чем сравнение указателей напрямую. А это почему постоянные строки лучше: они быстрее сравнивать и менее подвержены ошибкам.

если вы также хотите, чтобы ваша постоянная строка была глобальной, сделайте это так:

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

давайте использовать C++, так как моя цель C полностью отсутствует.

Если вы прячете строку в постоянную переменную:

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

Теперь, когда вы вызываете методы, вы используете my_string, вы используете строковую константу:

someMethod(mystring);

или, вы можете вызвать эти методы с помощью строкового литерала напрямую:

someMethod("my string");

причина, по-видимому, в том, что они поощряют вас использовать строковые константы, заключается в том, что Objective C не выполняет "интернирование"; то есть, когда вы используйте один и тот же строковый литерал в нескольких местах, на самом деле это другой указатель, указывающий на отдельную копию строки.

для ключей словаря это имеет огромное значение, потому что если я вижу, что два указателя указывают на одно и то же, это намного дешевле, чем делать сравнение всей строки, чтобы убедиться, что строки имеют одинаковое значение.

Edit: Майк, в C# строки неизменяемы, а литеральные строки с одинаковыми значениями все заканчиваются указывая на то же строковое значение. Я полагаю, что это верно и для других языков, которые имеют неизменяемые строки. В Ruby, который имеет изменяемые строки, они предлагают новый тип данных: символы ("foo" против :foo, где первая является изменяемой строкой, а вторая-неизменяемым идентификатором, часто используемым для хэш-ключей).