Frage zu strtok() - Threadsicher?



  • Ferner erwartet strtok_s keinen LPTSTR oder sonstige auf TCHAR aufbauende Typen und ist von der ganzen Problematik nicht betroffen.



  • Naja, das Projekt wird vielleicht aus mehr als strtok_s bestehen ...



  • Der vom Threadersteller gepostete Code enthielt nichts, was in diesem Zusammenhang kritisch wäre.

    Wenn es darum geht, ob es möglich ist, Code zu schreiben, der abhängig von bestimmten Projekteinstellungen kompilieren oder nicht kompilieren kann: Das ist der Fall. Ich halte das allerdings für keine sonderlich profunde Erkenntnis.



  • Es soll Windowsprogramme geben, die Windows-API Funktionen verwenden, und ein simples

    CopyFile("bla","fasel",0)
    

    wird unterschiedlich ablaufen, je nachdem, ob Unicode oder nicht.
    Deshalb ist die L/_TEXT/_T/wasweissich Anpassung für so verwendete Literale unumgänglich.
    Und da die meisten Quelltextautoren von der Auswertung von Rückgabewerten oder gar einer Fehlerbehandlung nicht viel halten und andere Quelltextautoren widerum vom Lesen von Compilerwarnungen ebensowenig, ist Nacharbeit und Anpassung im größeren Umfang nötig.



  • Und was hat das jetzt mit strtok_s() zu tun!? 🙄



  • Wutz schrieb:

    Es soll Windowsprogramme geben, die Windows-API Funktionen verwenden, und ein simples

    CopyFile("bla","fasel",0)
    

    wird unterschiedlich ablaufen, je nachdem, ob Unicode oder nicht.

    Ja, und deshalb sollte man eine nicht generisch, sondern als reines MultiByte - Projekt entwickelte Anwendung auch nach Wechsel der Entwicklungsumgebung weiterhin als MultiByte - Anwendung kompilieren.

    Ich meine, Ausgangspunkt dieser Diskussion war doch die Frage, ob man was am Code ändern müsse, wenn man auf eine jüngere Visual Studio - Version als IDE umsteigt. Die Tatsache, dass neu angelegte Projekte in diesen Versionen zunächst mal als Unicode - Projekte erstellt werden, ist da kein Argument für, weil diese Einstellung im Handumdrehen geändert werden kann, so daß auch weiterhin die entsprechenden Versionen der WinApi - Funktionen übersetzt werden.

    Es gibt doch nur drei plausible Möglichkeiten:
    Der alte Code ist entweder nur MB-tauglich, möglicherweise ist er auch nur Unicode-tauglich, oder er ist, was den Zeichensatz angeht, generisch.

    In allen drei Fällen kann die IDE so eingestellt werden, dass der Code übersetzt werden kann, ohne am Code ändern zu müssen.



  • Abgesehen davon betrifft das alles strtok_s() in keiner Weise...



  • Wer lesen kann ist klar im Vorteil.



  • Hier mal eine Variante, die dir den Umstieg auf eine neue Compilerversion nur wegen einer fehlenden Funktion ersparen kann, hatte ich irgendwann schon mal gezeigt, kann ich aber jetzt nicht finden.
    Multithreadfähigkeit/Reentranz ist hierbei gegeben:

    char *strtok_reentrant(char *s,const char *c,char **m)
    {
      char *p=s?s:*m;
      if( !*p )
        return 0;
      while( *c && !(*m=strchr(p,*c)) ) ++c;
      if( *c )
        *(*m)++=0;
      else
        *m=p+strlen(p);
      return p;
    }
    
    int main()
    {
      char x[]="1;2;;4",
           y[]="1-2;3-4;;-8",
           *dummy1,*dummy2,*p1,*p2;
    
      for(p1=strtok_reentrant(x,";",&dummy1);p1;p1=strtok_reentrant(0,";",&dummy1))
        puts(p1);
    
      for(p1=strtok_reentrant(y,";",&dummy1);p1;p1=strtok_reentrant(0,";",&dummy1))
        for(p2=strtok_reentrant(p1,"-",&dummy2);p2;p2=strtok_reentrant(0,"-",&dummy2))
          puts(p2);
    
      return 0;
    }
    

    Zu bemerken wäre noch, dass hier "leere" Felder nicht (wie bei strtok) ignoriert werden.



  • Es scheint mir sinnvoller, da mit strspn und strpbrk zu arbeiten. Außerdem empfiehlt sich für bekannte Plattformen, auf die von ihnen bereitgestellten Varianten auszuweichen - es gilt das gleiche wie bei memcpy etc.: Standardfunktionen sind im Zweifel besser optimiert als alles, was man sich selbst in ein paar Minuten zusammenhacken kann.

    Ich denke da an etwas in dieser Art:

    #include <stddef.h>
    #include <string.h>
    
    #if defined(unix) || defined(__unix) || defined(__unix__)
    #include <unistd.h>
    #endif
    
    char *strtok_reentrant(char *str, char const *delim, char **saveptr) {
    #if defined(_MSC_VER) && _MSC_VER >= 1400
      return strtok_s(str, delim, saveptr);
    #elif defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112L
      return strtok_r(str, delim, saveptr);
    #else
      char *token;
    
      if(str == NULL) str = *saveptr;
    
      /* Führende Trenner überspringen */
      str += strspn(str, delim);
    
      if(*str != '\0') {
        /* Stelle merken */
        token = str;
        /* Nächsten Trenner suchen... */
        str = strpbrk(token, delim);
    
        if(str) {
          /* ...falls vorhanden, da Terminator einfügen und Stelle merken... */
          *str = '\0';
          *saveptr = str + 1;
        } else {
          /* ...sonst nur Stelle merken, damit bei nächsten Aufruf
           * automatisch NULL herauskommt. */
          *saveptr = token + strlen(token);
        }
      } else {
        /* Das hier ist reine Vorsicht für eine strenge Lesart des POSIX-Standards.
         * Auf diese Weise kann strtok_reentrant erneut aufgerufen werden, nachdem
         * schon einmal NULL zurückgegeben wurde.
         */
        *saveptr = str;
        return NULL;
      }
    
      return token;
    #endif
    }
    

Anmelden zum Antworten