2010-05-22 4 views
3

gcc 4.4.4 C89différence des chaînes de largeur fixe et des chaînes terminées par zéro

je suis entré dans une discussion récente sur les « chaînes de largeur fixe » et « zéro » des chaînes terminées.

Quand j'y pense. Ils semblent être la même chose. Une chaîne avec un nul final.

à savoir

char *name = "Joe bloggs"; 

est une chaîne largeur fixe qui ne peut pas être changé. Et a également un nul final. Dans la discussion, on m'a aussi dit que strncpy ne devrait jamais être utilisé sur des «chaînes terminées par zéro».

Un grand merci pour tout susgestions,

+0

Contexte (je pense): http://stackoverflow.com/questions/2884874/when-to-use-strncpy-or-memmove –

Répondre

7

Le terme «chaîne de largeur fixe» fait généralement référence à quelque chose de complètement différent.

Une chaîne de largeur fixe de N est une chaîne de caractères N, où tous les caractères N sont garantis être initialisés. Si vous voulez représenter une chaîne plus courte, vous devez remplir votre chaîne avec zéro caractère à la fin. Vous devez ajouter autant de caractères zéro que nécessaire pour utiliser tous les caractères N. Notez que si vous devez stocker une chaîne de longueur exactement N, une chaîne de largeur fixe aura aucun caractère à la fin. C'est à dire. En général, les chaînes à largeur fixe sont et non zéro terminé!

Quel est le but de ceci? Le but de ceci est de sauvegarder 1 caractère lors du stockage de la chaîne de longueur maximale possible. Si vous utilisez des chaînes de largeur fixe N, vous avez besoin exactement de N caractères pour représenter une chaîne de longueur N. Comparez cela aux chaînes terminées par zéro ordinaires, ce qui nécessiterait N + 1 caractère (caractère supplémentaire pour le terminateur zéro).

Pourquoi est-il complété avec des zéros à la fin? Il est complété de zéros pour simplifier la comparaison lexicographique des chaînes à largeur fixe. Vous comparez simplement tous les caractères N jusqu'à ce que vous atteigniez la différence. Notez que l'on peut utiliser absolument n'importe quel caractère pour remplir la chaîne de largeur fixe en longueur complète. Assurez-vous simplement d'obtenir la bonne commande lexicographique. Utiliser un caractère nul pour le remplissage est un bon choix.

Quand est-ce utile?Très rarement. Les économies réalisées par les chaînes à largeur fixe sont rarement importantes dans le traitement de chaîne générique: ces économies sont trop petites et ne se produisent que dans les cas où la largeur est utilisée par la chaîne. Mais ils pourraient s'avérer utiles dans certains cas spécifiques.

D'où vient tout cela? Un exemple classique de «chaîne à largeur fixe» est un champ de nom de fichier large de 14 caractères dans une ancienne version du système de fichiers Unix. Il était représenté par un tableau de 14 caractères et une représentation de largeur fixe a été utilisée. À ce moment, l'enregistrement d'un caractère sur un nom de fichier complet (tous les 14 caractères) était important.

Maintenant à strncpy. La fonction strncpy a été spécifiquement introduite pour initialiser ces champs de noms de fichiers larges de 14 caractères dans ce système de fichiers. La fonction strncpy a été spécifiquement créée pour générer une chaîne de longueur fixe valide: elle effectue la conversion d'une chaîne terminée par zéro en une chaîne de largeur fixe. Malheureusement, il a reçu un nom trompeur, ce qui explique pourquoi de nombreuses personnes le confondent avec une fonction de copie "sécurisée" pour les chaînes à zéro. Ce dernier est une compréhension totalement erronée du but et de la fonctionnalité de strncpy. L'utilisation de littéraux chaîne pour représenter les chaînes à largeur fixe (comme dans votre exemple) n'est pas une bonne idée, car les littéraux chaîne ajoutent toujours un caractère nul à la fin, et les chaînes à largeur fixe ne le font pas nécessairement. Voici comment un groupe de chaînes de largeur fixe peut être initialisé dans un programme C

char fw_string1[7] = { 'T', 'h', 'i', 's', ' ', 'i', 's' }; 
char fw_string2[7] = { 's', 't', 'r', 'i', 'n', 'g' }; 
char fw_string3[7] = { 'H', 'e', 'l', 'l', 'o' }; 

Tous les tableaux ont le même nombre d'éléments - 7. Notez que la première chaîne n'est pas zéro terminée, tandis que les autres sont Zéro-rembourré. Conversion de la chaîne « ordinaire » en un regardera largeur fixe comme suit

char fw_string4[7]; 

strncpy(fw_string4, "Hi!", 7); 

Dans ce cas, la fonction strncpy est utilisée exactement ce qu'il était destiné à être utilisé. Notez également que, hormis la fonction de conversion strncpy, la bibliothèque standard ne fournit pratiquement aucun moyen de travailler avec des chaînes à largeur fixe. Vous devez essentiellement les traiter comme des tableaux de caractères bruts et implémenter manuellement les opérations de niveau supérieur. La plupart des opérations de base seront naturellement implémentées par des fonctions du groupe mem.... memcmp, pour un exemple, mettra en œuvre la comparaison.

P.S. En utilisant le commentaire de caf, on peut utiliser en langage C des littéraux pour initialiser des chaînes à largeur fixe, puisque le langage C permet à l'initialisateur littéral d'être un caractère plus long que le tableau (ie en C c'est OK, si le zéro final ne rentre pas dans le tableau). Donc, ce qui précède peut être réécrite comme équivalente

char fw_string1[7] = "This is"; 
char fw_string2[7] = "string"; 
char fw_string3[7] = "Hello"; 

Notez que fw_string1 est toujours pas zéro terminé dans ce cas.

+0

Grand répondre. Belle fin de la discussion du fil d'origine. +1 –

+0

Vous pouvez également utiliser des littéraux de chaîne pour initialiser ces tableaux de longueur fixe; cela aura exactement le même effet. – caf

+0

@caf: En fait, vous avez raison. En C (mais pas en C++), vous pouvez initialiser un tableau de caractères avec un littéral de chaîne même si le zéro final ne rentre pas dans le tableau. – AnT

1

Tout d'abord, je pense que vous voulez dire chaîne de longueur fixe, et non fixe avec une ficelle. Deuxièmement, ce qui précède est une chaîne terminée par zéro. Il ne devrait pas être changé en raison de sa définition en tant que constante littérale.

AFAIK C n'a pas de véritables "chaînes de longueur fixe". Au mieux, vous pouvez définir un tampon de taille N et ne pas y placer plus de N-1 caractères, où placer plus serait une erreur et oublier le terminateur NULL peut être une erreur. En ce qui concerne strncpy, il copie le nombre de caractères spécifié, et zéro le reste. Cela signifie que si la destination n'est pas assez longue, vous écririez au-delà de l'espace disponible ou n'auriez pas de terminateur NULL sur votre chaîne, ce qui conduirait à des erreurs lorsque vous tenteriez d'utiliser la chaîne.

1

Je ne suis pas tout à fait sûr de l'expression "chaîne de largeur fixe". Selon la fonction C, les chaînes ont besoin ou n'ont pas besoin d'une terminaison \ 0. Des fonctions comme strlen et strcpy besoin de travailler sur \ 0 terminés chaînes afin de savoir quand arrêter. Les fonctions telles que strncpy n'ont pas besoin de mettre fin à la chaîne source, car un argument indique le nombre de caractères à copier. Lorsque vous déclarez le nom comme vous le faites, le contenu de ce nom est stocké dans la mémoire morte et ne peut pas être modifié, mais vous pouvez utiliser 'name' dans C fonctions qui ne modifient pas le contenu, par exemple.strlen (nom) ou lorsqu'il est utilisé comme source:

char mycopy[32]; 
strcpy(mycopy, name); 
Questions connexes