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

Я изучаю цель C и Какао и наткнулся на это утверждение:

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

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

25.08.2008 07:54:29
3 ОТВЕТА
РЕШЕНИЕ

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

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

С другой стороны, константные строки обычно объявляются и определяются с использованием следующего синтаксиса:

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

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

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

84
25.07.2012 04:04:38
Майк прав. Из книги "Программирование в Objective-C 2.0" - "Строка @" Программирование в Objective-C - это весело. \ N "- пример объекта строки с постоянными символами."
Josh Brown 26.03.2010 15:44:31
«Программирование в Objective-C 2.0» не является языковой справкой; ссылаться на это так, как если бы это было так, неверно. В C "foo" называется строковым литералом. Обычно «константа» относится к указателю или переменной, а не к литералу; литералы постоянны по определению.
Chris Hanson 29.03.2010 20:20:17
Лампочка зажглась !! Постоянные строки полезны, когда вы хотите эффективность перечислений, но не хотите чисел для значений. Отличный ответ, очень полезно!
bentford 15.06.2011 21:38:48

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

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

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

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

someMethod(mystring);

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

someMethod("my string");

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

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

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

3
25.08.2008 08:16:25

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

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

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

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

Константная строка будет const NSString* name = @"John";что эквивалентно NSString const* name= @"John";. Здесь и синтаксис, и намерение программиста ошибочны: const <object>игнорируется, а NSStringinstance ( 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];

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

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

// header
extern NSString *const name;
// implementation
NSString *const name = @"john";
12
24.01.2016 17:08:49