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

StackOverflow https://stackoverflow.com/questions/25746

  •  09-06-2019
  •  | 
  •  

Вопрос

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

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

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

Это было полезно?

Решение

В Objective-C синтаксис @"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 ключевое слово имеет значение;он гарантирует, что сам указатель будет постоянным.)

Хотя сжигание памяти не является такой большой проблемой, как это могло быть во времена рабочих станций 68030 с частотой 25 МГц и 8 МБ ОЗУ, сравнение строк на равенство может занять время.Помогает гарантировать, что в большинстве случаев строки, которые равны, также будут равны указателю.

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

Другие советы

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

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

Некоторые комментарии к последней строке:

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

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

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

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

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

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

5 Чтобы увидеть NSConstantString определение, нажмите cmd+щелкните его в Xcode.

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


Вернуться к вашей цитате

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

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

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

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

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

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

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

Давайте использовать C++, поскольку мой Objective C совершенно не существует.

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

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

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

someMethod(mystring);

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

someMethod("my string");

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top