Javas und C # Implementierung von String

8

In der Java- und C # -Implementierung von String ist die zugrunde liegende Information ein nullterminiertes char -Array wie in C / C ++?

(Zusätzlich zu anderen Informationen wie Größe usw.)

    
Daniel 08.09.2011, 18:14
quelle

3 Antworten

15

Nein. Es ist eine Folge von UTF-16 Code-Einheiten und einer Länge. Java- und C # -Strings können eingebettete NULs enthalten.

Jede UTF-16-Codeeinheit belegt zwei Bytes. Sie können sich also die Zeichenfolge "\nbytes\n" als:

vorstellen %Vor%

Beachten Sie, dass das letzte Byte in length nicht 0 ist. Das Feld substring gibt an, wie viele Bytes verwendet werden. Dies ermöglicht System.String sehr effizient zu sein - das gleiche Byte-Array wiederzuverwenden, aber mit einer anderen Länge (und einem Offset, wenn Ihre VM-Implementierung nicht in ein Array zeigen kann).

  

UTF-16 (16-Bit-Unicode-Transformationsformat) ist eine Zeichenkodierung für Unicode, die im Unicode-Coderaum von 0 bis 0x10FFFF 1.112.064-Nummern (sogenannte Codepunkte) codieren kann. Es erzeugt ein Ergebnis variabler Länge von einer oder zwei 16-Bit-Code-Einheiten pro Codepunkt.

Von javadoc

  

Eine Zeichenfolge stellt eine Zeichenfolge im UTF-16-Format dar, in der zusätzliche Zeichen durch Ersatzpaare dargestellt werden (weitere Informationen finden Sie im Abschnitt Unicode-Zeichenrepräsentationen in der Klasse "Zeichen"). Indexwerte beziehen sich auf Char-Code-Einheiten, daher verwendet ein Zusatzzeichen zwei Positionen in einem String.

C # unicode.org ist ähnlich definiert

  

Jedes Unicode-Zeichen in einer Zeichenfolge wird durch einen Unicode-Skalarwert definiert, der auch als Unicode-Codepunkt oder als ordinaler (numerischer) Wert des Unicode-Zeichens bezeichnet wird. Jeder Codepunkt wird unter Verwendung der UTF-16-Codierung codiert, und der numerische Wert jedes Elements der Codierung wird durch ein Zeichen dargestellt. Die resultierende Sammlung von Char-Objekten bildet den String.

Ich bin mir nicht sicher, ob C # gegen verwaiste Surrogate wacht, aber der obige Text scheint die Begriffe "Skalarwert" und "Codepunkt" zu mischen, was verwirrend ist. Ein Skalarwert wird also von .class :

definiert
  

Beliebiger Unicode-Codepunkt mit Ausnahme von Codecodes mit hohem und niedrigem Surrogat

Java nimmt definitiv die Codepoint-Ansicht und versucht nicht, sich gegen ungültige skalare Werte in Strings zu schützen.

"Strings Unveränderlichkeit und Persistenz" erklärt die Effizienzvorteile dieser Darstellung.

  

Einer der Vorteile der unveränderlichen Datentypen, über die ich hier schon gesprochen habe, ist, dass sie nicht nur unveränderlich sind, sondern auch "hartnäckig" sind. Mit "hartnäckig" meine ich einen unveränderlichen Datentyp, so dass gängige Operationen dieses Typs (wie das Hinzufügen eines neuen Elements zu einer Warteschlange oder das Entfernen eines Elements aus einer Struktur) den gesamten oder den gesamten Speicher vorhandener Daten wiederverwenden können Struktur. Da es alles unveränderlich ist, können Sie seine Teile wiederverwenden, ohne sich darum sorgen zu müssen, dass sie sich ändern.

BEARBEITEN: Das Obige ist sowohl in der Konzeption als auch in der Praxis wahr, aber VMs und CLRs haben die Freiheit, Dinge in bestimmten Situationen anders zu machen.

Die Java-Sprachspezifikation schreibt vor, dass Zeichenketten ausgelegt sind a bestimmte Weise in jstring files und seine JNI < Ein href="http://www.iam.ubc.ca/guides/javatut99/native1.1/implementing/string.html"> int32 length -Typ abstrahiert In-Memory-Darstellungsdetails, so dass eine VM es könnte stellen theoretisch eine Zeichenfolge im Speicher als eine NUL-terminierte UTF-8-Zeichenfolge mit einer Zwei-Byte-Form dar, die für eingebettete NUL-Zeichen anstelle der uint16[] bytes - und %code% -Darstellung verwendet wird, die effizienten wahlfreien Zugriff auf Codeeinheiten ermöglicht .

VMs tun dies jedoch nicht in der Praxis. "Der teuerste Ein-Byte-Fehler" argumentiert, dass NUL-terminierte Strings ein großer Fehler in C waren, Daher bezweifle ich, dass VMs sie aus Effizienzgründen intern übernehmen werden.

  

Der beste Kandidat, den ich mir vorstellen konnte, ist die C / Unix / Posix-Verwendung von NUL-terminierten Textstrings. Die Wahl war wirklich einfach: Soll die C-Sprache Strings als Adresse + Länge Tupel oder nur als die Adresse mit einem magischen Zeichen (NUL) das Ende markieren?

     

...

     

Das Nachdenken über virtuelle Speichersysteme erledigt diese Frage für uns. Das Optimieren der Bewegung einer Bytefolge bekannter Länge kann den Vorteil der vollen Breite von Speicherbussen und Cachezeilen nutzen, ohne jemals einen Speicherort zu berühren, der nicht Teil der Quell- oder Zielzeichenfolge ist.

     

Ein Beispiel ist die libc von FreeBSD, wo die bcopy (3) / memcpy (3) -Implementierung so viele Daten wie möglich in "unsigned long" -Bausteine, normalerweise 32 oder 64 Bits, verschiebt und dann alle nachfolgenden Bytes aufräumt "Wie der Kommentar es beschreibt, mit Byte-weiten Operationen.2

     

Wenn der Quellstring NUL-terminiert ist, riskiert der Versuch, in Einheiten größer als Bytes darauf zuzugreifen, den Versuch, Zeichen nach dem NUL zu lesen. Wenn das NUL-Zeichen das letzte Byte einer [virtueller Speicher] -Seite ist und die nächste [virtueller Speicher] -Seite nicht definiert ist, würde dies dazu führen, dass der Prozess aufgrund eines ungerechtfertigten "Seiten nicht vorhanden" -Fehlers abstürzt.

    
Mike Samuel 08.09.2011, 18:16
quelle
10

Als Implementierungsdetail ist ein String in der Microsoft-Implementierung der CLR im Speicher so angeordnet, wie ein BSTR in COM. (Einzelheiten zu BSTRs finden Sie unter Ссылка .)

Das heißt, eine Zeichenfolge wird als vier Bytes mit der Länge angeordnet, gefolgt von diesen vielen Zwei-Byte-UTF-16-Zeichen, gefolgt von zwei Bytes mit Null.

Natürlich ist es nicht notwendig , eine Zeichenfolge mit Längenvorgabe mit einem Nullzeichen zu beenden, aber es ist sicherlich bequem, dies zu tun, besonders wenn Sie die Szenarien betrachten, in denen Sie zwischen C # interoperieren müssen. Programme und nicht verwaltete C ++ - oder VB6-Programme. Der Marshaller kann manchmal etwas kopieren, weil er weiß, dass die Zeichenfolge bereits in einem Null-terminierten Format ist.

Wie gesagt, das ist ein Implementierungsdetail; Du solltest dich nicht darauf verlassen.

Ich weiß nicht, was Java macht.

    
Eric Lippert 08.09.2011 18:34
quelle
1

Ich kann nicht für C # sprechen, aber die String-Quelle von Java sagt nein. Größeninformationen des Arrays werden im Array gespeichert, sodass Sie keine Null-Terminierung benötigen.

%Vor%     
corsiKa 08.09.2011 18:18
quelle

Tags und Links