Quelles sont les différences entre strtok et strsep en C

Quelqu'un pourrait-il m'expliquer quelles sont les différences entre strtok() et strsep()? Quels sont les avantages et les inconvénients? Et pourquoi j'en choisirais un plutôt que l'autre.

18
demandé sur Jonathan Leffler 2011-08-28 06:11:24

2 réponses

à Partir de La Bibliothèque C de GNU manuel - trouver des jetons dans une chaîne:

Une différence entre strsep et strtok_r c'est que si la chaîne d'entrée contient plus d'un caractère de séparateur dans une rangée strsep renvoie une chaîne vide pour chaque paire de caractères de delimiter. Cela signifie qu'un programme normalement doit tester strsep retour une chaîne vide avant de la traiter.

6
répondu George Gaál 2014-12-06 23:35:16

Une différence majeure entre strtok() et strsep() que strtok() est normalisée (par la norme, et donc aussi par POSIX) mais strsep() n'est pas standardisé (par C ou POSIX; il est disponible dans la bibliothèque GNU C, et provient de BSD). Ainsi, le code portable est plus susceptible d'utiliser strtok()strsep().

une autre différence est que les appels à strsep() fonction sur différentes chaînes peuvent être intercalées, alors que vous ne pouvez pas faire cela avec strtok() (si vous pouvez le faire avec strtok_r()). Donc, à l'aide de strsep() dans une bibliothèque ne casse pas accidentellement un autre code, alors qu'utiliser strtok() dans une fonction de bibliothèque doit être documenté parce que l'autre code en utilisant strtok() en même temps ne peut pas appeler la fonction de bibliothèque.

la page de manuel pour strsep()kernel.org dit:

la fonction strsep() a été introduite en remplacement de strtok(3), puisque cette dernière ne peut pas gérer des champs vides.

ainsi, l'autre différence majeure est celle mise en évidence par George Gaál dans sa réponse; strtok() permet des délimiteurs multiples entre un même token, alors que strsep() attend un seul délimiteur entre les tokens, et interprète les délimiteurs adjacents comme un jeton vide.

strsep() et strtok() modifier leurs chaînes d'entrée et ne permet pas non plus d'identifier quel caractère de délimiteur a marqué la fin du token (parce que les deux écrivent un NUL!--21--> le séparateur après la fin du jeton).

Quand les utiliser?

  • Vous utilisez strsep() quand vous voulez des tokens vides plutôt que d'autoriser des délimiteurs multiples entre les tokens, et quand vous ne vous souciez pas de la portabilité.
  • Vous utilisez strtok_r() quand vous voulez autoriser plusieurs délimiteurs entre les tokens et que vous ne voulez pas de tokens vides (et POSIX est suffisamment portable pour vous).
  • Vous utilisez uniquement strtok() quand quelqu'un menace votre vie si vous ne le faites pas. Et que vous souhaitez l'utiliser assez longtemps pour vous sortir de la vie en danger; il vous faudra alors renoncer à tout usage une fois de plus. Il est toxique; ne l'utilisez pas. Il serait mieux d'écrire votre propre strtok_r() ou strsep() utilisation strtok().

Pourquoi strtok() toxique?

strtok() la fonction est toxique si elle est utilisée dans une fonction de la bibliothèque. Si votre fonction de bibliothèque utilise strtok(), il doit être clairement expliquées.

c'est parce Que:

  1. si une fonction d'appel utilise strtok() et appelle la fonction qui utilise aussi strtok(), vous brisez la fonction d'appel.
  2. Si votre fonction appelle une fonction qui s'appelle strtok(), ce qui va casser l'utilisation de strtok().
  3. si votre programme est multithread, au plus un thread peut utiliser strtok() à tout moment-sur une séquence de strtok() appeler.

La racine de ce problème est l'état sauvegardé entre les appels qui permet strtok() pour continuer là où elle s'est arrêtée. Il n'y a pas d'autre moyen raisonnable de résoudre le problème que "ne pas utiliser strtok()".

  • Vous pouvez utiliser strsep() si elle est disponible.
  • vous pouvez utiliser POSIX's strtok_r() si elle est disponible.
  • vous pouvez utiliserstrtok_s() si elle est disponible.
  • Nominalement, vous pouvez utiliser L'annexe K. 3 de la norme ISO/IEC 9899:2011.7.3.1 fonction strtok_s(), mais son interface est différente des deux strtok_r() et Microsoft strtok_s().

BSD strsep():

char *strsep(char **stringp, const char *delim);

POSIX strtok_r():

char *strtok_r(char *restrict s, const char *restrict sep, char **restrict state);

Microsoft strtok_s():

char *strtok_s(char *strToken, const char *strDelimit, char **context);

Annexe K strtok_s():

char *strtok_s(char * restrict s1, rsize_t * restrict s1max,
               const char * restrict s2, char ** restrict ptr);

notez qu'il y a 4 arguments, pas 3 comme dans les deux autres variantes sur strtok().

30
répondu Jonathan Leffler 2017-09-30 21:17:15