Quelle est la différence entre une constante de chaîne et un littéral de chaîne?

J'apprends objective-C et Cocoa et j'ai rencontré cette Déclaration:

Les frameworks Cocoa s'attendent à ce que des constantes de chaîne globales plutôt que des littéraux de chaîne soient utilisés pour les clés de dictionnaire, les noms de notification et d'exception, et certains paramètres de méthode prenant des chaînes.

Je n'ai travaillé que dans des langages de niveau supérieur, donc je n'ai jamais eu à considérer autant les détails des chaînes. Quelle est la différence entre une constante de chaîne et un littéral de chaîne?

58
demandé sur R.. 2008-08-25 11:54:29

3 réponses

En Objective-C, la syntaxe @"foo" est un immuable, littéral exemple de NSString. Il ne fait pas une chaîne constante à partir d'un littéral de chaîne comme Mike le suppose.

Les compilateurs Objective-C typiquement font les chaînes littérales internes dans les unités de compilation - c'est - à-dire qu'elles fusionnent plusieurs utilisations de la même chaîne littérale-et il est possible pour l'éditeur de liens de faire un internement supplémentaire à travers les unités de compilation directement liées en un seul binaire. (Depuis Cocoa distingue les chaînes mutables et immuables, et les chaînes littérales sont toujours immuables, cela peut être simple et sûr.)

Constante chaînes d'autre part sont généralement déclarés et définis en utilisant la syntaxe comme ceci:

// MyExample.h - declaration, other code references this
extern NSString * const MyExampleNotification;

// MyExample.m - definition, compiled for other code to reference
NSString * const MyExampleNotification = @"MyExampleNotification";

Le point de l'exercice syntaxique ici est que vous pouvez rendre utilise la chaîne efficace en vous assurant qu'il n'y a qu'une seule instance de cette chaîne en cours d'utilisation Même dans plusieurs frameworks (bibliothèques partagées) dans le même espace d'adressage. (Le placement du mot clé const est important; il garantit que le pointeur lui-même est garanti constant.)

Bien que la gravure de mémoire ne soit pas aussi importante qu'à l'époque des stations de travail 25MHz 68030 avec 8MB de RAM, la comparaison des chaînes pour l'égalité peut prendre du temps. S'assurer que la plupart des chaînes de temps égales seront également égales par pointeur aide.

Disons, par exemple, que vous souhaitez vous abonner aux notifications à partir d'un objet par son nom. Si vous utilisez des chaînes non constantes pour les noms, le NSNotificationCenter affichant la notification pourrait finir par faire beaucoup de comparaisons de chaînes octet par octet lors de la détermination de qui s'y intéresse. Si la plupart de ces comparaisons sont court-circuitées parce que les chaînes comparées ont le même pointeur, cela peut être une grande victoire.

82
répondu Chris Hanson 2012-07-25 04:04:38

, Quelques définitions

Un littéral est une valeur immuable par définition. par exemple: 10
Une constante est une variable ou un pointeur en lecture seule. par exemple: const int age = 10;
Un chaîne littérale est une expression comme @"". Le compilateur le remplacera par une instance de NSString.
Une constante de chaîne {[31] } est un pointeur en lecture seule sur NSString. par exemple: NSString *const name = @"John";

Quelques commentaires sur la dernière ligne:

  • c'est un pointeur constant, pas une constante objet1. objc_sendMsg2 ne se soucie pas si vous vous qualifiez l'objet avec const. Si vous voulez un objet immuable, vous devez coder cette immuabilité à l'intérieur de l'objet3.
  • toutes les expressions @"" sont en effet immuables. Ils sont remplacés4 au moment de la compilation avec des instances de NSConstantString, qui est une sous-classe spécialisée de NSString avec une disposition de mémoire fixe5. Cela explique également pourquoi NSString est le seul objet qui peut être initialisé à la compilation le temps6.

Une chaîne constante {[31] } serait const NSString* name = @"John"; ce qui équivaut à NSString const* name= @"John";. Ici, la syntaxe et l'intention du programmeur sont fausses: const <object> est ignoré, et l'instance NSString (NSConstantString) était déjà immuable.

1 Le mot-clé const s'applique s'applique à tout ce qui est immédiatement à sa gauche. Si rien n'est à sa gauche, il s'applique à tout ce qui est immédiatement à sa droite.

2 C'est la fonction que le runtime utilise pour envoyer tous les messages dans Objective-C, et donc ce que vous pouvez utiliser pour changer l'état d'un objet.

3 Exemple: en const NSMutableArray *array = [NSMutableArray new]; [array removeAllObjects]; const n'empêche pas la dernière instruction.

4 Le code LLVM qui réécrit l'expression est RewriteModernObjC::RewriteObjCStringLiteral dans RewriteModernObjC.rpc.

5 Pour voir la NSConstantString définition, cmd+clic dans Xcode.

6 la Création de la compilation les constantes pour d'autres classes seraient faciles mais il faudrait que le compilateur utilise une sous-classe spécialisée. Cela casserait la compatibilité avec les anciennes versions D'Objective-C.


Retour à votre devis

Les frameworks Cocoa s'attendent à ce que les constantes de chaîne globales les littéraux de chaîne sont utilisés pour les clés de dictionnaire, la notification et noms d'exception, et certains paramètres de méthode qui prennent des chaînes. Vous devrait toujours préférer les constantes de chaîne sur les littéraux de chaîne lorsque vous avoir un choix. En utilisant des constantes de chaîne, vous faites appel à l'aide de compilateur pour vérifier votre orthographe et ainsi éviter les erreurs d'exécution.

Il dit que les littéraux sont sujets aux erreurs. Mais il ne dit pas qu'ils sont aussi plus lents. Comparer:

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

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

Dans le second cas, j'utilise des clés avec des pointeurs const, donc à la place [a isEqualToString:b], je peux faire (a==b). L'implémentation de isEqualToString: compare le hachage et exécute ensuite la fonction C strcmp, donc elle est plus lente que comparer les pointeurs directement. Ce qui est pourquoi les chaînes constantes sont meilleures: elles sont plus rapides à comparer et moins sujettes aux erreurs.

Si vous voulez aussi que votre chaîne constante soit globale, faites-le comme ceci:

// header
extern NSString *const name;
// implementation
NSString *const name = @"john";
12
répondu Jano 2016-01-24 17:08:49

Utilisons C++, puisque mon objectif C est totalement inexistant.

Si vous stockez une chaîne dans une variable constante:

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

Maintenant, quand vous appelez les méthodes, vous utilisez my_string, vous utilisez une constante de chaîne:

someMethod(mystring);

, Ou, vous pouvez appeler ces méthodes avec le littéral de chaîne directement:

someMethod("my string");

La raison, vraisemblablement, qu'ils vous encouragent à utiliser des constantes de chaîne est parce que Objective C ne fait pas "interning"; c'est-à-dire, lorsque vous utilisez le même littéral de chaîne dans plusieurs endroits, c'est en fait un pointeur différent pointant vers une copie séparée de la chaîne.

Pour les clés du dictionnaire, Cela fait une énorme différence, car si je peux voir que les deux pointeurs pointent vers la même chose, c'est beaucoup moins cher que d'avoir à faire une comparaison de chaîne entière pour s'assurer que les chaînes ont une valeur égale.

Edit: Mike, en C # les chaînes sont immuables, et les chaînes littérales avec des valeurs identiques pointent toutes vers la même valeur de chaîne. J'imagine que la vrai pour d'autres langues qui ont des chaînes immuables. Dans Ruby, qui a des chaînes mutables, ils offrent un nouveau type de données: symbols ("foo" vs.: foo, où le premier est une chaîne mutable, et le second est un identifiant immuable souvent utilisé pour les clés de hachage).

3
répondu Brad Wilson 2008-08-25 08:16:25