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

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

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

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

Ответ 1

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

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

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

Ответ 2

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

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

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

  • Это постоянный указатель, а не постоянный объект 1. objc_sendMsg 2 не волнует, если вы квалифицируете объект с помощью 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.cpp.

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

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

суб >


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

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

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

// 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";

Ответ 3

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

Если вы вставляете строку в константу:

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

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

someMethod(mystring);

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

someMethod("my string");

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

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

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