Es fällt mir schwer zu glauben, dass ich die erste Person bin, die auf dieses Problem stößt, aber lange gesucht hat und keine Lösung gefunden hat.
Ich würde gerne strncpy verwenden, aber sollte es UTF8-fähig sein, damit es nicht teilweise ein utf8-Zeichen in die Zielzeichenfolge schreibt.
Andernfalls können Sie nie sicher sein, dass der resultierende String ein gültiges UTF8 ist, auch wenn Sie die Quelle kennen (wenn die Quellzeichenfolge größer als die maximale Länge ist).
Das Überprüfen der resultierenden Zeichenfolge kann funktionieren, aber wenn dies als viel bezeichnet werden soll, ist es besser, eine strncpy-Funktion zu haben, die danach sucht.
glib hat g_utf8_strncpy
, aber dies kopiert eine bestimmte Anzahl von Unicode-Zeichen, während Im nach einer Kopierfunktion sucht, die um die Bytelänge begrenzt ist.
Um klar zu sein, durch "utf8 aware" , meine ich, dass es die Grenze des Zielpuffers nicht überschreiten sollte und niemals nur einen Teil einer utf kopieren soll -8 Zeichen. (Eine gültige utf-8-Eingabe darf niemals dazu führen, dass eine ungültige utf-8-Ausgabe ausgegeben wird.)
Einige Antworten haben darauf hingewiesen, dass strncpy
alle Bytes nullt und dass es keine Null-Beendigung gewährleistet. Im Nachhinein hätte ich nach einem utf8 aware strlcpy
gefragt, allerdings zu der Zeit, als ich es nicht getan habe kenne die Existenz dieser Funktion nicht.
Um auf die eigene Frage zu antworten, gibt es die C-Funktion, mit der ich endete (C ++ für dieses Projekt nicht verwenden):
Hinweise:
- Erkenne, dass dies kein Klon von strncpy
für utf8 ist, sondern eher wie strlcpy
von openbsd.
- utf8_skip_data kopiert von glib's gutf8.c
- Es validiert nicht die utf8 - was ich beabsichtigt habe.
Hoffe, das ist nützlich für andere und interessiert an Feedback, aber bitte keine pedantischen Zeloten über NULL
Abbruchverhalten, es sei denn, es ist ein tatsächlicher Fehler oder irreführendes / inkorrektes Verhalten.
Danke an James Kanze, der dafür die Basis lieferte, aber unvollständig war und C ++ (ich brauche eine C-Version).
%Vor% Ich bin mir nicht sicher, was Sie unter UTF-8 verstehen. strncpy
kopiert Bytes, nicht
Zeichen, und die Größe des Puffers wird auch in Bytes angegeben. Ob
Was du meinst ist, dass es nur vollständige UTF-8-Zeichen kopiert,
zum Beispiel, wenn es keinen Platz für den nächsten Charakter gibt, bin ich
sich einer solchen Funktion nicht bewusst ist, aber es sollte nicht zu schwer sein zu schreiben:
(Der Inhalt der Tabelle in utf8Size ist ein bisschen schmerzhaft zu erzeugen, aber das ist eine Funktion, die Sie verwenden werden, wenn Sie damit zu tun haben UTF-8, und Sie müssen es nur einmal tun.)
Ich habe dies an vielen Beispiel-UTF8-Strings mit Multi-Byte-Zeichen getestet. Wenn die Quelle zu lang ist, führt sie eine umgekehrte Suche durch (beginnt am Nullabschlusszeichen) und arbeitet rückwärts, um das letzte vollständige UTF8-Zeichen zu finden, das in den Zielpuffer passen kann. Es stellt immer sicher, dass das Ziel null beendet ist.
%Vor%Hier ist eine C ++ Lösung:
u8string.h
:
u8slbcpy.cpp
:
Die Funktion u8slbcpy()
hat eine C-Schnittstelle, ist aber in C ++ implementiert. Meine Implementierung verwendet die Header-only UTF8-CPP-Bibliothek .
Ich denke, dass dies so ziemlich das, was Sie suchen, aber beachten Sie, dass es immer noch das Problem, dass ein oder mehr Kombinationszeichen kopiert werden möglicherweise nicht, wenn die Kombination von Zeichen auf den gelten n < sup> th Zeichen (selbst kein Kombinationszeichen) und der Zielpuffer ist gerade groß genug, um die UTF-8-Codierung von Zeichen zu speichern 1 bis n , aber nicht die Kombination von Zeichen des Zeichens n . In diesem Fall werden die Bytes, die die Zeichen 1 bis n darstellen, geschrieben, aber keines der kombinierenden Zeichen von n . In der Tat könnte man sagen, dass das n th -Zeichen teilweise geschrieben ist.
strncpy()
ist eine schreckliche Funktion:
Auch wenn die Zeichen im ASCII-Bereich (0x7f und darunter) bleiben, ist die resultierende Zeichenfolge nicht das, was Sie wollen. In dem UTF-8-Fall ist es möglich, dass die Endung und in keiner ungültigen UTF-8-Sequenz endet.
Der beste Rat ist, strncpy()
zu vermeiden.
BEARBEITEN: ad 1):
%Vor%Einverstanden, der Puffer wird nicht überlaufen. Aber das Ergebnis ist immer noch unerwünscht. strncpy () löst nur einen Teil des Problems. Es ist irreführend und unerwünscht.
UPDATE (2012-10-31): Da dies ein unangenehmes Problem ist, habe ich mich entschieden, meine eigene Version zu hacken und das hässliche strncpy () Verhalten nachzuahmen. Der Rückgabewert ist jedoch die Anzahl der kopierten Zeichen.
%Vor%Um die obige Antwort zu kommentieren, ist "strncpy () eine schreckliche Funktion:". Ich hasse es sogar, solche pauschalen Aussagen zu kommentieren, auf Kosten der Schaffung eines weiteren Internetprogrammierung-Jihad, aber irgendwie wird diese Aussage irreführend für diejenigen sein, die hierher kommen, um nach Antworten zu suchen.
Okay, vielleicht sind C-String-Funktionen "Old School". Vielleicht sollten alle Strings in C / C ++ in irgendeiner Art von intelligenten Containern usw. sein, vielleicht sollte man C ++ anstelle von C verwenden (wenn Sie eine Wahl haben), sind diese eher eine Vorliebe und ein Argument für andere Themen. p>
Ich kam hierher, um nach einem UTF-8 strncpy () zu suchen. Nicht, dass ich es nicht machen könnte (die Codierung ist IMHO einfach und elegant), sondern wollte sehen, wie andere ihre gemacht haben und vielleicht eine in ASM optimierte finden.
Um das "Geschenk der Götter" der Programmierwelt Menschen, legen Sie Ihre Hybris für einen Moment beiseite und schauen Sie sich einige Fakten.
Es gibt nichts Falsches an "strncpy ()", oder irgendeine andere der ähnlichen Funktionen mit den gleichen Nebenwirkungen und Problemen wie "_snprintf ()", etc.
Ich sage: "strncpy () ist nicht schrecklich", sondern "schreckliche Programmierer benutzen es schrecklich".
Was "schrecklich" ist, ist nicht die Regeln zu kennen. Aus Sicherheitsgründen (wie Pufferüberlauf) und Programmstabilitätsimplikationen würde es auch nicht notwendig sein, dass Microsoft beispielsweise "Safe String Functions" zu seiner CRT-Bibliothek hinzufügt, wenn die Regeln genau befolgt werden.
Die wichtigsten:
So handle ich persönlich mit solchen Dingen und anderen Regeln, die nur bekannt und geübt werden sollen.
Ein handliches Makro für die statische Stringgröße:
%Vor%Beim Deklarieren von lokalen / Stack-String-Puffern:
A) Die Größe ist zum Beispiel auf 1023 + 1 für den Terminator begrenzt, um Strings mit bis zu 1023 Zeichen Länge zu ermöglichen.
B) Ich initialisiere die Zeichenkette auf Null in der Länge, plus endet am Ende, um eine mögliche 'n' Trunkierung abzudecken.
%Vor%Alternativ könnte man einfach tun: %Code% natürlich, aber dann gibt es eine Performance-Implikation für einen Compiler generiert "memset () wie Aufruf, um den gesamten Puffer auf Null. Es macht Dinge sauberer für das Debuggen, und ich bevorzuge diesen Stil für statische (vs lokale / Stack) Strings Puffer / p>
Nun ein "strncpy ()" nach den Regeln:
%Vor%Natürlich gibt es andere "Regeln" und Probleme, aber das sind die wichtigsten, die einem einfallen. Sie müssen einfach wissen, wie die lib-Funktionen funktionieren und sichere Methoden wie diese verwenden.
Schließlich benutze ich in meinem Projekt sowieso ICU , also habe ich beschlossen, mitzugehen und die Makros in "utf8" zu verwenden. h "mein eigenes" strncpy () "zu machen.