Comment fonctionne l'implémentation de strchr
J'ai essayé d'écrire ma propre mise en œuvre de la strchr() la méthode.
Il ressemble maintenant à ceci:
char *mystrchr(const char *s, int c) {
while (*s != (char) c) {
if (!*s++) {
return NULL;
}
}
return (char *)s;
}
La dernière ligne était à l'origine
return s;
Mais cela n'a pas fonctionné parce que s est const. J'ai trouvé qu'il doit être jeté (char *), mais honnêtement, je ne sais pas ce que je fais là 🙁 quelqu'un Peut m'expliquer?
source d'informationauteur Marc
Vous devez vous connecter pour publier un commentaire.
Je crois que c'est en fait une faille dans la Norme C de la définition de la
strchr()
fonction. (Je serai heureux d'avoir tort.) (Réponse aux commentaires, on peut se demander si c'est vraiment une faille; à mon humble avis c'est encore une mauvaise conception. Il peut être utilisé en toute sécurité, mais il est trop facile de l'utiliser de manière non sûre.)Voici ce que la norme C dit:
Ce qui signifie que ce programme:
même si soigneusement définit le pointeur vers la chaîne de caractères littérale comme un pointeur vers
const
char
a un comportement indéfini, car il modifie la chaîne littérale. gcc, au moins, de ne pas avertir à ce sujet, et le programme meurt avec une erreur de segmentation.Le problème est que
strchr()
prend unconst char*
argument, ce qui signifie qu'il s'engage à ne pas modifier les données quis
points -- mais elle renvoie une plainechar*
qui permet à l'appelant de modifier les mêmes données.Voici un autre exemple;
il n'a pas un comportement indéfini, maistranquillement modifie unconst
objet qualifié sans aucune jette (qui, à la réflexion, je crois qu'il a un comportement indéfini):Ce qui signifie, je pense, (pour répondre à votre question) C mise en œuvre de
strchr()
a jeté son résultat pour le convertir deconst char*
àchar*
ou de faire quelque chose d'équivalent.C'est pourquoi C++, dans l'un des quelques changements qu'il apporte à la bibliothèque C standard, remplace
strchr()
avec deux fonctions surchargées du même nom:De cours C ne peut pas le faire.
Une autre solution aurait été de remplacer
strchr
par deux fonctions, l'une tenant unconst char*
et retour d'unconst char*
et une autre de prendre unchar*
et retour d'unchar*
. Contrairement au C++, les deux fonctions doivent avoir des noms différents, peut-êtrestrchr
etstrcchr
.(Historiquement,
const
a été ajouté à C aprèsstrchr()
a déjà été défini. Ce fut probablement la seule façon de garderstrchr()
sans casser le code existant.)strchr()
n'est pas la seule fonction de la bibliothèque C standard qui a ce problème. La liste de la fonction concernée (je pense cette liste est complète, mais je ne garantis pas) est:(tous déclaré dans
<string.h>
) et:(déclarée dans
<stdlib.h>
). Toutes ces fonctions prennent un pointeur surconst
de données qui pointe vers le premier élément d'un tableau, et le retour d'un non-const
pointeur sur un élément de ce tableau.La pratique du retour de la non-const pointeurs vers const données non-modification des fonctions est en fait un idiome assez largement utilisés dans la langue. Il n'est pas toujours joli, mais il est assez bien établi.
La reationale ici est simple:
strchr
par lui-même est un non-modification de l'opération. Nous avons pourtant besoin destrchr
fonctionnalités pour les deux chaînes constantes et non constantes chaînes de caractères, ce qui permettrait aussi de propager la constness de l'entrée à la constness de la sortie. Ni C pas du C++ fournir tout support élégant pour ce concept, ce qui signifie que, dans les deux langues, vous aurez à écrire deux pratiquement identique fonctions afin d'éviter de prendre des risques avec la const-correctness.En C++, vous wild être en mesure d'utiliser la fonction de surcharge en déclarant les deux fonctions avec le même nom
Dans C vous n'avez pas de surcharge de fonctions, afin de mettre pleinement en œuvre la const-correctness dans ce cas, vous devez fournir les deux fonctions avec différents noms, quelque chose comme
Bien que, dans certains cas, cela pourrait être la bonne chose à faire, c'est généralement (et à juste titre), jugé trop lourd et impliquant par C normes. Vous pouvez résoudre ce problème en un plus compact (mais plus risqué) par la mise en œuvre d'une seule fonction
qui renvoie non-const pointeur dans la chaîne d'entrée (à l'aide d'un plâtre à la sortie, exactement comme vous l'avez fait). À noter que cette approche ne viole pas les règles de la langue, mais il fournit l'appelant avec les moyens de les violer. En rejetant la constness des données de cette approche simplement délègue la responsabilité à l'observer const-correction de la fonction elle-même à l'appelant. Aussi longtemps que l'appelant est au courant de ce qui se passe et se souvient de "jouer bien", c'est à dire utilise un const qualifiés pointeur de const données, les brèches dans le mur de la const-correctness créée par cette fonction sont réparés immédiatement.
Je vois ce truc comme une approche parfaitement acceptable pour réduire inutile duplication de code (en particulier en l'absence de la surcharge de fonction). La bibliothèque standard utilise. Vous n'avez aucune raison d'éviter qu'il soit, en supposant que vous comprenez ce que vous faites.
Maintenant, pour votre mise en œuvre de
strchr
il semble bizarre pour moi de la stylistique point de vue. Je voudrais utiliser le cycle de l'en-tête pour itérer sur l'ensemble de la gamme, nous travaillons sur (la chaîne), et l'utilisation de l'intérieurif
pour attraper la résiliation anticipée de la conditionMais des choses comme ça sont toujours une question de préférence personnelle. Quelqu'un pourrait préférez
Certains pourraient dire que le fait de modifier les paramètres de la fonction (
s
) à l'intérieur de la fonction est une mauvaise pratique.La
const
mot-clé signifie que le paramètre ne peut pas être modifié.Vous ne pouvait pas retourner
s
directement parce ques
est déclarée commeconst char *s
et le type de retour de la fonction estchar *
. Si le compilateur permettait de le faire, il serait possible de remplacer leconst
restriction.L'ajout d'un cast explicite
char*
indique au compilateur que vous savez ce que vous faites (même si, comme Eric l'a expliqué, il serait mieux si vous ne l'avez pas).Mise à JOUR: Pour des raisons de contexte, je suis en citant Eric réponse, puisqu'il semble l'avoir supprimé:
La Fonction renvoie la Valeur doit être un Pointeur Constant vers un Personnage:
strchr
accepte unconst char*
et doit retournerconst char*
aussi. Vous êtes de retour d'une non constante qui est potentiellement dangereux car la valeur de retour de points dans la saisie de caractères tableau (l'appelant peut s'attendre à un argument constant afin de rester constant, mais il est modifiable lorsqu'il s'est retourné comme unchar *
pointeur).La Fonction renvoie la Valeur NULL si Aucun Caractère correspondant est Trouvé:
Aussi
strchr
est censé renvoyerNULL
si l'cherché caractère n'est pas trouvé. Si elle renvoie non NULLE lorsque le caractère n'est pas trouvé, ou s dans ce cas, l'appelant (s'il estime que le comportement est le même que strchr)pourrait supposer que le premier caractère dans le résultat des matchs (sans la valeur de retour NULL
il n'y a aucun moyen de dire si il y avait un match ou pas).
(Je ne suis pas sûr si c'est ce que vous avez l'intention de le faire.)
Voici un Exemple d'une Fonction qui Fait Cela:
J'ai écrit et a couru plusieurs tests sur cette fonction; j'ai ajouté un peu de vraiment évident vérifications pour éviter les accidents potentiels: