Was ist der Unterschied zwischen strtok_r und strtok_s in C?

Lesezeit: 9 Minuten

Ich versuche, diese Funktion in einem C-Programm zu verwenden, das in Linux und Windows kompiliert werden muss. Zuerst habe ich versucht, strtok_r zu verwenden, aber dann, als ich unter Windows kompiliert habe, hat es sich über die nicht vorhandene Funktion beschwert und gesagt, es würde davon ausgehen, dass es sich um eine externe Funktion handelt, ist dann aber fehlgeschlagen. Ich habe dann strtok_s verwendet und es kompiliert! Dann habe ich es unter Linux versucht, aber jetzt beschwert es sich, dass es einen “undefinierten Verweis auf ‘strtok_s'” gibt.

Ist eine eine reine Windows-Funktion und die andere eine Linux-Funktion??? Was kann ich tun, damit es auf beiden kompiliert wird?

  • strtok_r() ist POSIX; strtok_s() ist Windows. Normal verwenden strtok() die in allen Implementierungen verfügbar ist (unterstützt C89).

    – pmg

    26. Januar 2012 um 16:37 Uhr

  • Das Problem ist, dass ich eine Zeichenfolge strtok muss, während ich eine andere Zeichenfolge strtok-ing, weshalb ich diese brauche, da sie den Status speichert.

    – Petranaja

    26. Januar 2012 um 16:39 Uhr

  • @pmg – es sei denn, Sie benötigen Thread- oder Pufferüberlaufsicherheit

    – Martin Beckett

    26. Januar 2012 um 16:40 Uhr

  • @MartinBeckett Warte was? Wo rettet es den Staat? Es gibt nur zwei Argumente, eines ist NULL (auf dem zweiten Token), das andere ist das Zeichen, das Sie finden möchten. Ich möchte in der Lage sein, eine Zeichenfolge zu strtok, etwas in dieser Zeichenfolge zu finden und diese zu strtok, dann zur ursprünglichen Zeichenfolge zurückzukehren und sie weiter zu strtok.

    – Petranaja

    26. Januar 2012 um 16:46 Uhr

  • Dies ist eine alte Frage, aber ich hatte das Bedürfnis, darauf hinzuweisen, dass strtok_s C11 ist, nicht nur Windows.

    – Remmy

    25. Januar 2015 um 15:33 Uhr

strtok_s ist einfach die Windows-Version von strtok_r was sonst überall Standard ist.

Eine (ich denke, übliche) Möglichkeit, ein Programm portabel zu machen, wenn es um Funktionen wie strtok_s/strtok_r ist der Präprozessor zu verwenden:

#if defined(_WIN32) || defined(_WIN64)
/* We are on Windows */
# define strtok_r strtok_s
#endif

Da die Prototypen und die Funktionalität gleich sind, können Sie jetzt nur noch verwenden strtok_r.

  • Dies würde wahrscheinlich brechen, wenn Sie auf Cygwin kompilieren, das sich selbst als Windows meldet, aber Posix-Schnittstellen wie hat strtok_r bereits definiert. Verwenden Sie so etwas wie #ifndef HAVE_STRTOK_R (und es in den Build-Skripten zu erkennen) wäre besser.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Januar 2012 um 16:38 Uhr

  • @R ..: Cygwin definiert tatsächlich nicht _WIN32 (oder _WIN64) aus genau diesem Grund – es wird häufig verwendet, um Code zu identifizieren, der nicht Unix-ähnlich ist. Cygwin definiert __CYGWIN__ und __unix__ stattdessen

    – Chris Dodd

    23. April 2013 um 22:17 Uhr

  • Es kann gut sein zu wissen, dass es einen anderen gibt strtok_s in C11 mit einer ganz anderen Signatur: en.cppreference.com/w/c/string/byte/strtok

    – Tor Klingeberg

    6. Januar 2017 um 14:37 Uhr

  • @ChrisDodd Es gibt immer noch Probleme mit MinGW. MinGW vordefiniert _WIN32 aber es unterstützt strtok_r. Ich denke, es ist besser, das zu überprüfen _MSC_VER Makro.

    – Viktor

    15. Februar 2019 um 3:01 Uhr


Diese beiden Funktionen sind wirklich hässliche, nicht intuitive Redewendungen zum Analysieren von Zeichenfolgen und erfüllen normalerweise die Anforderungen Ihrer speziellen Anwendung auf subtile Weise nicht. Noch mehr für die Ebene strtok in Standard-C. Werfen Sie sie einfach weg und schreiben Sie Ihren eigenen Code, um die zu durchlaufen char Array und brechen Sie es nach Bedarf auf. strchr, strspnund strcspn kann dabei hilfreich sein, oder Sie können das Array einfach von Grund auf neu bearbeiten.

  • Können Sie etwas mehr darüber erklären, warum diese Funktionen schlecht sind? Es erscheint mir intuitiver, als Zeichen für Zeichen durchzugehen und nach Dingen zu suchen.

    – Petranaja

    26. Januar 2012 um 16:52 Uhr

  • (1) Das Trennzeichen wird überschrieben/verloren. Wenn Sie also nicht nur ein mögliches Trennzeichen haben, verlieren Sie Informationen. (2) mehrere aufeinanderfolgende Trennzeichen werden als eines behandelt, was sinnvoll ist, wenn Ihr Trennzeichen ein Leerzeichen ist, aber nicht, wenn es beispielsweise ein Komma ist.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Januar 2012 um 17:01 Uhr

  • Bitte beachten Sie das sicherlich in etwas Situationen, die strtok Semantik ist genau das, was Sie wollen, und das einzige Problem ist die Statefulness (was strtok_r und strtok_s Fix). Ich stelle nur fest, dass jedes Mal, wenn ich versuchte, sie zu verwenden, es mindestens einen Aspekt meiner Analyseanforderungen gibt, die sie nicht unterstützen, und es am Ende einfacher ist, den Code einfach direkt zu schreiben.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Januar 2012 um 17:03 Uhr

  • -1: Zum Parsen einer Zeichenfolge, die in einen temporären Puffer eingelesen wurde, bei der Sie die Trennzeichen wegwerfen und nur die Zeichenfolgen gültig haben möchten, bis Sie mit dem Parsen fertig sind, ist strtok genau das, was Sie wollen, und strtok_r/strtok_s ist viel besser da es reentrant ist.

    – Chris Dodd

    23. April 2013 um 22:19 Uhr


Benutzer-Avatar
BeReal82

Ich habe nicht genug Ruf, um andere Antworten zu kommentieren, also muss ich meine eigenen geben.

1) Um diese Aussage anzusprechen:

“strtok_s ist eine pufferüberlaufsichere Version von strtok unter Windows. Die Standard-strtok unter Windows ist Thread-sicher…”

Das ist nicht wahr. strtok_s ist die threadsichere Version für den MSVC-Compiler. strtok ist nicht threadsicher!

2) Um diese Aussage anzusprechen:

“Dies würde wahrscheinlich brechen, wenn Sie auf Cygwin kompilieren, das sich selbst als Windows meldet, aber POSIX-Schnittstellen wie hat strtok_r bereits definiert.”

Wieder nicht wahr. Der Unterschied besteht darin, welchen Compiler Sie verwenden. Bei Verwendung des Visual C++-Compilers von Microsoft, MSVC, lautet die Funktion strtok_s. Ein anderer Compiler, wie beispielsweise die GNU Compiler Collection, GCC, kann eine andere Standardbibliotheksimplementierung verwenden, wie z strtok_r. Denken Sie beim Identifizieren der zu verwendenden Funktion an den Compiler und nicht an die Zielplattform.

Meiner Meinung nach ist die Antwort von Joachim Pileborg die beste auf dieser Seite. Es bedarf jedoch einer kleinen Bearbeitung:

#if defined(_WIN32) /* || defined(_WIN64) */
#define strtok_r strtok_s
#endif

Sowohl _WIN32 als auch _WIN64 sind vordefinierte Makros, die vom MSVC-Compiler bereitgestellt werden. _WIN64 wird beim Kompilieren eines 64-Bit-Ziels definiert. _WIN32 ist sowohl für 32- als auch für 64-Bit-Ziele definiert. Dies ist ein Kompromiss, den Microsoft aus Gründen der Abwärtskompatibilität eingegangen ist. _WIN32 wurde erstellt, um die Win32-API anzugeben. Jetzt sollten Sie _WIN32 in Betracht ziehen, um die Windows-API anzugeben – es ist nicht spezifisch für ein 32-Bit-Ziel.

  • Beim ersten Punkt liegen Sie falsch: strtok ist Thread-sicher unter Windows, da zwei verschiedene Threads diese Funktion innerhalb desselben Prozesses sicher verwenden können, selbst wenn strtok andere Probleme hat, wie in einer anderen Antwort von @JameyKirby erläutert.

    – Antoine L

    24. Februar 2014 um 20:10 Uhr

  • MinGW vordefiniert _WIN32 aber es unterstützt strtok_ralso ist es besser, die zu überprüfen _MSC_VER Makro.

    – Viktor

    15. Februar 2019 um 3:02 Uhr


Benutzer-Avatar
James Kirby

Nur um klarzustellen. strtok ist Thread-sicher in Windows. strtok verwendet a TLS -Variable, um den letzten Zeiger für jeden Thread beizubehalten. Allerdings können Sie nicht verwenden strtok um den Zugriff auf mehr als einen Token-String pro Thread zu verschachteln. strtok_r und strtok_s beide gehen dieses Verschachtelungsproblem an, indem sie es dem Benutzer ermöglichen, den Kontext über den dritten Parameter aufrechtzuerhalten. Hoffe das hilft.

strtok_r ist eine Thread-sichere Version von strtok auf POSIX-Systemen

strtok_s ist eine pufferüberlaufsichere Version von strtok unter Windows. Der Standard-strtok unter Windows ist Thread-sicher, also sollte strtok_s es sein.

  • strtok_r ist Teil von POSIX und seit Jahren (Jahrzehnten?)

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Januar 2012 um 16:36 Uhr

  • Ich denke immer noch, dass die Antwort nicht sehr nützlich ist, da sie nur das abdeckt, was OP (meistens) bereits wusste, und nicht, wie das Problem gelöst werden kann.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Januar 2012 um 16:45 Uhr

  • @R – die Lösung ist, dass Sie strok_r unter Posix und strtok_s unter Windows verwenden können, Joachims Lösung beschreibt, wie. ODER Sie können Windows nur mit dem Posix-Subsystem programmieren

    – Martin Beckett

    26. Januar 2012 um 16:46 Uhr

  • @MartinBeckett es ist C11 Annex K Standard, nicht nur Windows 🙂

    – Alexander Ricio

    20. Dezember 2017 um 6:13 Uhr

  • @Alexander Riccio Microsoft strtok_s und C11 strtok_s sind komplett anders! Microsoft strtok_s hat nur 3 Parameter, während C11 strtok_s hat 4 Parameter. Der Prototyp von Microsoft strtok_s ist char* strtok_s(char* str, const char* delimiters, char** context); während der Prototyp von C11 strtok_s ist char *strtok_s(char *restrict str, rsize_t *restrict strmax, const char *restrict delim, char **restrict ptr);.

    – Viktor

    15. Februar 2019 um 3:11 Uhr


MinGW definiert auch vor _WIN32 aber es unterstützt strtok_ralso halte ich es nicht für eine gute Idee, das zu überprüfen _WIN32 Makro. Es ist besser, die zu überprüfen _MSC_VER Makro, das das Makro für Microsoft Visual Studio ist.

#ifdef _MSC_VER
#define strtok_r strtok_s
#endif

ACHTUNG: Microsoft strtok_s und C11 strtok_s sind komplett anders! Microsoft strtok_s hat nur 3 Parameter, während C11 strtok_s hat 4 Parameter, so dass es in Zukunft ein kompatibles Problem sein kann.

Der Prototyp von Microsoft strtok_s ist

char* strtok_s(char* str, const char* delimiters, char** context);

Der Prototyp von C11 strtok_s ist

char *strtok_s(char *restrict str, rsize_t *restrict strmax, const char *restrict delim, char **restrict ptr);

  • strtok_r ist Teil von POSIX und seit Jahren (Jahrzehnten?)

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Januar 2012 um 16:36 Uhr

  • Ich denke immer noch, dass die Antwort nicht sehr nützlich ist, da sie nur das abdeckt, was OP (meistens) bereits wusste, und nicht, wie das Problem gelöst werden kann.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    26. Januar 2012 um 16:45 Uhr

  • @R – die Lösung ist, dass Sie strok_r unter Posix und strtok_s unter Windows verwenden können, Joachims Lösung beschreibt, wie. ODER Sie können Windows nur mit dem Posix-Subsystem programmieren

    – Martin Beckett

    26. Januar 2012 um 16:46 Uhr

  • @MartinBeckett es ist C11 Annex K Standard, nicht nur Windows 🙂

    – Alexander Ricio

    20. Dezember 2017 um 6:13 Uhr

  • @Alexander Riccio Microsoft strtok_s und C11 strtok_s sind komplett anders! Microsoft strtok_s hat nur 3 Parameter, während C11 strtok_s hat 4 Parameter. Der Prototyp von Microsoft strtok_s ist char* strtok_s(char* str, const char* delimiters, char** context); während der Prototyp von C11 strtok_s ist char *strtok_s(char *restrict str, rsize_t *restrict strmax, const char *restrict delim, char **restrict ptr);.

    – Viktor

    15. Februar 2019 um 3:11 Uhr


1354110cookie-checkWas ist der Unterschied zwischen strtok_r und strtok_s in C?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy