Your Browser is not longer supported

Please use Google Chrome, Mozilla Firefox or Microsoft Edge to view the page correctly
Loading...

{{viewport.spaceProperty.prod}}

Strings

&pagelevel(4)&pagelevel

Der Java-Datentyp string wird im JNI als Datentyp jstring bereitgestellt. Dieser Typ kann in C nicht direkt verwendet werden, insbesondere hat er nichts mit dem C-Datentyp char * gemein. Um den String in eine Form zu konvertieren, die in C bearbeitbar ist, müssen die entsprechenden JNI-Schnittstellen zur Konvertierung benutzt werden (siehe JNI-Dokumentation).

Der Java-Datentyp char wird an der JNI-Schnittstelle als Datentyp jchar bereitgestellt. Dieser ist mit dem C-Datentyp unsigned short kompatibel und repräsentiert ein Zeichen in Unicode-Darstellung. Unicode ist für die ersten 256 Zeichen identisch mit der ASCII-Codierung nach ISO8859-1. Für Unicode-Zeichen außerhalb dieses Bereiches gibt es in C/C++ im BS2000 keinerlei Support, die Verarbeitung solcher Zeichen muss also vom Anwender selbst vorgenommen werden.

Eine besondere Rolle spielt die UTF-8-Darstellung von Unicode, die von Java im JNI teilweise verwendet wird. In der UTF-8-Darstellung werden Unicode-Zeichen in ein, zwei oder drei Bytes verschlüsselt. Dabei sind die Unicode-Zeichen mit der Codierung 1 bis 127 mit diesem Wert in einem Byte dargestellt, was wiederum exakt der ASCII-Codierung dieser Zeichen entspricht.

Außerdem werden von Java UTF-8 Bytefolgen immer mit einem NULL-Byte abgeschlossen, was die Verarbeitung als C-Strings ermöglicht. Um das zu erreichen, wird das Unicode-NULL-Zeichen in zwei Byte verschlüsselt, um eine Verwechslung mit dem String-Ende in C zu vermeiden, denn im Gegensatz zu C dürfen in Java Strings durchaus auch NULL-Zeichen enthalten.

Für die Verarbeitung von UTF-8-Bytefolgen in C gelten also folgende einfache Regeln:

  • Das NULL-Byte kennzeichnet das Ende der Bytefolge und ist zwingend notwendig.

  • Bytes, für die die Funktion isascii_ascii() den Wert „true“ liefert (1-127), sind auch tatsächlich ASCII-Zeichen nach ISO8859-1

  • Für alle anderen Bytes gilt, dass sie Bestandteil von Mehr-Byte-Folgen zur Darstellung von Unicode-Zeichen außerhalb des Bereiches 1-127 sind. Diese müssen vom Anwender selbst interpretiert werden.

Da fast alle diese Konvertierungsfunktionen Zeichenfolgen zumindest in einer zu ASCII aufwärtskompatiblen Form darstellen, spielt die Code-Umsetzung von ASCII nach EBCDIC und umgekehrt im BS2000 eine besondere Rolle. Dies gilt natürlich nicht nur für Strings, sondern auch z.B. für Byte-Arrays oder Characters (jchar).

Wenn hier von ASCII die Rede ist, dann ist immer der Zeichensatz ISO8859-1 (ISO-Latin1) oder sein 7-Bit Ableger (ISO 646) gemeint. Bei EBCDIC ist der Zeichensatz DF04-1 (Internationale Referenzversion) mit vertauschtem 0x15 und 0x25 bzw. sein 7-Bit-Ableger DF03-1 gemeint.

Neben expliziten Konvertierungsmöglichkeiten stehen für die Unterstützung von ASCII-Strings entsprechende Compiler- und Laufzeitsystem-Erweiterungen bereit, die es erlauben, direkt mit ASCII-Strings und Zeichen in C zu arbeiten.

Explizite Konvertierung

Die Konvertierungsfunktionen des JNI (siehe „Java TM Native Interface “ [13]) arbeiten im BS2000 exakt wie spezifiziert. Sie liefern bzw. erwarten immer Unicode oder UTF-8.

Für die explizite Konvertierung zwischen ASCII (8859-1) und EBCDIC (DF04-1) stehen einige Funktionen im CRTE zur Verfügung. Diese sind deklariert in einem Headerfile <ascii_ebcdic.h>, das Bestandteil der CRTE-Distribution ist. Diese Konvertierungsfunktionen sind im Handbuch „CRTE“ [3] beschrieben.



Beispiel

Das folgende Beispiel zeigt die Verwendung in einer native Methode, die den Wert einer Umgebungsvariablen ermittelt und von diesem das Präfix JAVA_ entfernt. Auf Java-Seite sei die Methode deklariert als:

public native String get_jenviron(String name);

Das zugehörige C-Programm könnte folgendermaßen aussehen:

#include <jni.h> 
#include ".....h"         // von javah generierter Header
#include <stdlib.h>
#include <ascii_ebcdic.h>
JNIEXPORT jstring JNICALL 
Java_..._get_jenviron(JNIEnv *env, jobject jthis, 
                      jstring name)
{ 
    const char *utf_name; 
    char *ebcdic_name, *ebcdic_value, *utf_value; 
    jstring value;
    utf_name = (env*)->GetStringUTFChars(env,name,NULL),
    ebcdic_name = _a2e_dup(utf_name); 
    (*env)->ReleaseStringUTFChars(env,name,utf_name); 
    ebcdic_value = getenv(ebcdic_name); 
    free(ebcdic_name); 
    if (ebcdic_value == NULL) 
      return NULL;
    if (strncmp(ebcdic_value,"JAVA_",5) == 0) 
      utf_value = _e2a_dup(ebcdic_value+5); 
    else 
      utf_value = _e2a_dup(ebcdic_value); 
    value = (*env)->NewStringUTF(env,utf_value); 
    free(utf_value); 
    return value; 
}

Der obige Beispielcode enthält keinerlei Fehlerbehandlung. Es wird implizit davon ausgegangen, dass in allen Strings nur Zeichen des 7-Bit-ASCII-Zeichensatzes vorkommen. Außerdem ist dieser Code natürlich stark BS2000-spezifisch.

ASCII-Strings im C-Code

Der C/C+-Compiler ab der Version 3.0B hat die Möglichkeit, alternativ zum normalen EBC-DIC-Encoding für String- und Character-Literale auch ein entsprechendes ASCII-Encoding zu generieren. Diese Einstellung muss für eine ganze Compilations-Einheit (Source-Datei) gelten und wird über die Compiler-Optionen -Kliteral_encoding_ascii bzw. -Kliteral_encoding_ascii_full gesteuert. Der Unterschied der beiden Optionen bezieht sich auf die Behandlung von Oktal- und Hexadezimal-Sequenzen in solchen Literalen. Die Umwandlung von solchen Literalteilen unterbleibt bei -Kliteral_encoding_ascii.

ASCII-Strings im C-Laufzeitsystem

Das C-Laufzeitsystem hat neben den o.g. Konvertierungsroutinen noch weitere Unterstützung für die Nutzung von ASCII-Strings und -Zeichen. Alle wesentlichen XPG4-Funktionen, die mit Strings oder Zeichen arbeiten oder solche liefern, stehen in einer Variante für ASCII-Codierung bereit. Beim Setzen einer der in Abschnitt „ASCII-Strings im C-Code" beschriebenen Compiler-Optionen für ASCII-Nutzung werden normalerweise automatisch die entsprechenden Library-Funktionen benutzt, ohne dass der Anwender dafür etwas tun muss. Für den Mischbetrieb können Sie das Verhalten auch verändern (siehe Handbuch „CRTE“ [3]).

Ist gleichzeitig die Compiler-Option -Kieee_floats gesetzt, so werden die kombinierten AS-CII/IEEE-Varianten benutzt (z.B. bei printf).

Ab dem C-Compiler V3.1A und CRTE V2.4C werden die Argumente des Vektors argv[] bei der Compilierung des Main-Programms mit einer der in Abschnitt „ASCII-Strings im C-Code" beschriebenen Compiler-Optionen als ASCII-Strings übergeben. Die globalen Variablen des C-Laufzeitsystems tzname und die Strings von environ werden als ASCII-Strings gespeichert. Die explizite Konvertierung von argv[] entfällt damit.

Falls explizit auf die Strings der globalen Variablen tzname oder environ zugegriffen wird, so ist zu beachten, dass diese Strings seit JENV V1.4B als ASCII-Strings abgelegt sind (vorher EBCDIC-Strings). Vom expliziten Zugriff auf die Variable environ wird aber durch den Technical Standard „The Single UNIX Specification“ abgeraten (siehe „X/Open System Interface (XSI) Specification“ [16]). Der implizite Zugriff über getenv() und putenv() funktioniert wie bisher kompatibel zu Vorversionen.



Beispiel

Das obige C-Programm könnte mit diesen Möglichkeiten jetzt folgendermaßen aussehen:

#include <jni.h> 
#include ".....h" //        von javah generierter Header 
#include <stdlib.h>
JNIEXPORT jstring JNICALL 
Java_..._get_jenviron(JNIEnv *env, jobject jthis, 
                      jstring name) 
{ 
   const char *utf_name;
   char *utf_value;
   utf_name = (*env)->GetStringUTFChars(env,name,NULL); 
   utf_value = getenv(utf_name); 
   (*env)->ReleaseStringUTFChars(env,name,utf_name); 
   if (utf_value == NULL) 
       return NULL;
   if (strncmp(utf_value,"JAVA_",5) == 0) 
     return (*env)->NewStringUTF(env,utf_value+5); 
   else 
     return (*env)->NewStringUTF(env,utf_value); 
}

Dies entspricht vollständig einer Implementierung, die auch auf Unix-Systemen zum Einsatz kommen könnte. Daher ist diese Form sicher am ehesten für portierten Code zu empfehlen.