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

Quelqu’un pourrait-il m’expliquer les différences entre strtok() et strsep() ? Quels sont leurs avantages et inconvénients? Et pourquoi devrais-je choisir un sur l’autre.

Extrait du manuel de la bibliothèque GNU C – Recherche de jetons dans une chaîne :

Une différence entre strsep et strtok_r est que si la chaîne d’entrée contient plus d’un caractère du délimiteur d’une ligne, strsep renvoie une chaîne vide pour chaque paire de caractères du délimiteur. Cela signifie qu’un programme devrait normalement tester strsep renvoyant une chaîne vide avant de la traiter.

Une différence majeure entre strtok() et strsep() est que strtok() est normalisé (par le standard C, et donc aussi par POSIX), mais strsep() n’est pas normalisé (par C ou POSIX; il est disponible dans GNU C Bibliothèque et a son origine sur BSD). Ainsi, le code portable est plus susceptible d’utiliser strtok() que strsep() .

Une autre différence est que les appels à la fonction strsep() sur différentes chaînes peuvent être entrelacés, alors que vous ne pouvez pas le faire avec strtok() (bien que vous puissiez le faire avec strtok_r() ). Ainsi, l’utilisation de strsep() dans une bibliothèque ne rompt pas accidentellement le code, alors que l’utilisation de strtok() dans une fonction de bibliothèque doit être documentée, car un autre code utilisant strtok() ne peut pas appeler la fonction de bibliothèque.

La page de manuel de strsep() sur kernel.org indique:

La fonction strsep () a été introduite pour remplacer strtok (3), cette dernière ne pouvant pas gérer les champs vides.

Ainsi, l’autre différence majeure est celle soulignée par George Gaál dans sa réponse; strtok() autorise plusieurs délimiteurs entre un seul jeton, alors que strsep() attend un seul délimiteur entre les jetons et interprète les délimiteurs adjacents comme un jeton vide.

strsep() et strtok() modifient leurs chaînes d’entrée et ne permettent pas d’identifier le caractère de délimitation marqué la fin du jeton (car les deux écrivent un NUL '\0' sur le séparateur après la fin du jeton).

Quand les utiliser?

  • Vous utiliseriez strsep() lorsque vous voulez des jetons vides plutôt que de permettre plusieurs délimiteurs entre les jetons, et lorsque la portabilité ne vous dérange pas.
  • Vous devez utiliser strtok_r() lorsque vous souhaitez autoriser plusieurs délimiteurs entre les jetons et que vous ne voulez pas de jetons vides (et que POSIX est suffisamment portable pour vous).
  • Vous n’utiliseriez strtok() lorsque quelqu’un menacerait votre vie si vous ne le faites pas. Et vous ne l’utiliseriez que pendant assez longtemps pour vous sortir de la situation en danger de mort; vous en abandonneriez alors l’usage. C’est toxique; ne l’utilise pas. Il serait préférable d’écrire votre propre strtok_r() ou strsep() plutôt que d’utiliser strtok() .

Pourquoi strtok() toxique?

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

C’est parce que:

  1. Si une fonction appelante utilise strtok() et appelle votre fonction qui utilise également strtok() , vous interrompez la fonction appelante.
  2. Si votre fonction appelle une fonction qui appelle strtok() , l’utilisation de strtok() sera interrompue.
  3. Si votre programme est multithread, au plus un thread peut utiliser strtok() à un moment donné, au cours d’une séquence d’appels strtok() .

La racine de ce problème est l’état enregistré entre les appels qui permet à strtok() de continuer là où il s’était arrêté. Il n’existe aucun moyen sensé de résoudre le problème autre que “n’utilisez pas strtok() “.

  • Vous pouvez utiliser strsep() s’il est disponible.
  • Vous pouvez utiliser la fonction strtok_r() de POSIX si elle est disponible.
  • Vous pouvez utiliser Microsoft strtok_s() s’il est disponible.
  • Nominalement, vous pouvez utiliser la fonction strtok_s() l’ISO / CEI 9899: 2011, Annexe K.3.7.3.1, mais son interface est différente de strtok_r() et de strtok_s() de Microsoft.

strsep() BSD strsep() :

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

POSIX strtok_r() :

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

Microsoft strtok_s() :

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

Annexe K strtok_s() :

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

Notez que cela a 4 arguments, pas 3 comme dans les deux autres variantes sur strtok() .