Einführung in Zeichen und Zeichenfolgen in C-Sprache für Swift Programmer

Überprüfungsumgebung

Terminal: MacBook Air OS: macOS High Sierra Swift: 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2) Clang: Apple LLVM version 9.0.0 (clang-900.0.39.2)

Überblick

Ich denke, jeder verwendet beiläufig die folgende Methode, wenn er eine C-Zeichenfolge (char \ *) in eine Swift- oder Objective-C-Zeichenfolge (Zeichenfolge, NSString) konvertiert.

String.swift


init?(cString: UnsafePointer<CChar>) //typealias CChar = Int8

Zunächst möchte ich den cString vorstellen, der an diese Methode übergeben wird, dh den C-String. Als nächstes wurde das obige Verfahren auf der NSString-Seite abgeschafft, und ein Verfahren zum gleichzeitigen Festlegen der Codierung wird wie unten gezeigt vorbereitet. Ich möchte über den zu diesem Zeitpunkt übergebenen Codierungswert nachdenken.

String.swift


init?(cString: UnsafePointer<CChar>, encoding enc: String.Encoding)

Über den Buchstaben C.

Char wird als Typ bereitgestellt, der ein Zeichen in C-Sprache darstellt. In dieser Variablen vom Typ char kann ein 1-Byte-Wert gespeichert werden. Der Buchstabe C schließt den Buchstaben in einfache Anführungszeichen ein. Der in einfache Anführungszeichen eingeschlossene Wert wird als Zeichenliteral bezeichnet.

C Brief.c


int main(void) {
    char c = '*'; //「'Es wird in einen 1-Byte-ASCII-Wert konvertiert, indem das Zeichen mit einer "Markierung" versehen wird.
    printf("%c\n", c); // *
    printf("%ld\n", sizeof(c)); // 1

}

Wie in den Kommentaren erwähnt, ist das Obige tatsächlich die folgende Zuckerbeschichtungssyntax.

Buchstabe c.c


int main(void) {
    char c = 42;
    printf("%c\n", c); // *
    printf("%ld\n", sizeof(c)); // 1
}

Mit anderen Worten, die Substanz des Zeichenliteral ist "nur eine Zahl".

Wenn Sie Multi-Byte-Zeichen wie unten gezeigt in einfache Anführungszeichen setzen, überschreitet die generierte Zahl (* 1) die Größe von "char" (1 Byte), was zu einem Kompilierungsfehler führt.

(\ * 1: Den generierten Wert finden Sie im folgenden Abschnitt "[Wenn Mehrbytezeichen in der C-Zeichenfolge gespeichert sind](https://qiita.com/ysn551/items/446074b22103233edd95#c%E3%81] % AE% E6% 96% 87% E5% AD% 97% E5% 88% 97% E3% 81% AB% E3% 83% 9E% E3% 83% AB% E3% 83% 81% E3% 83% 90 % E3% 82% A4% E3% 83% 88% E6% 96% 87% E5% AD% 97% E3% 82% 92% E6% A0% BC% E7% B4% 8D% E3% 81% 97% E3 % 81% 9F% E5% A0% B4% E5% 90% 88) ”)

C Brief.c


//Diese Quellcodedatei wird in UTF8 gespeichert
int main(void) {
    char c = 'Ah'; // error: character too large for enclosing character 
}

Mit anderen Worten, Multi-Byte-Zeichen können nicht wie in Variablen vom Typ char gespeichert werden.

Darüber hinaus kann die Überprüfung, dass das tatsächliche Zeichenliteral eine 1-Byte-Zahl ist, durch die Tatsache bewiesen werden, dass der Wert direkt im int-Typ (4 Byte) gespeichert werden kann, wie unten gezeigt.

Die Substanz des Zeichenliteral ist eine 1-Byte-Zahl.c


int main(void) {
    int num = 'abcd';
    printf("%0x\n", num); // 64656667
}

Das Ergebnis der Ausgabe des Werts von num in Hexadezimalzahl ist "64656667". Wenn Sie den Wert in Byteeinheiten lesen, können Sie sehen, dass er in "64,65,66,67" zerlegt werden kann.

Zusammenfassung hier

Über die Zeichenkette von C.

Eine C-Sprachzeichenfolge ist ein Array vom Typ "char". Mit anderen Worten wird es durch ein Array zum Speichern von 1-Byte-Daten dargestellt. Außerdem schließt die C-Zeichenfolge das Zeichen in doppelte Anführungszeichen ein. Der in doppelte Anführungszeichen eingeschlossene Wert wird auch als Zeichenfolgenliteral bezeichnet.

C-Saite.c


int main(void) {
    char str[] = "Hello"; //Die Anzahl der Elemente kann durch gleichzeitiges Initialisieren weggelassen werden.
    printf("sizeof(str)/sizeof(char) = %ld\n", sizeof(str)/sizeof(char)); // 6
}

Die oben für die Initialisierung verwendete Zeichenfolge * Hallo * besteht aus 5 Zeichen, die Anzahl der Elemente beträgt jedoch 6. Tatsächlich hat es die folgende Syntax für die Zuckerbeschichtung.

Über die Zeichenkette von C..c


int main(void) {
    char str[] = {'H','e','l','l','o','\0'};
    printf("sizeof(str)/sizeof(char) = %ld\n", sizeof(str)/sizeof(char)); //6
}

Mit anderen Worten, das Zeichenfolgenliteral "Hallo" gibt ein Zeichenarray mit 6 Elementen zurück, in dem das Nullzeichen am Ende gespeichert ist.

Zusammenfassung hier

Wenn Mehrbyte-Zeichen in der C-Zeichenfolge gespeichert sind

Obwohl im obigen Abschnitt nicht erwähnt, werden die Ergebnisse, wenn der Quellcode wie unten gezeigt mit Multibyte-Zeichen initialisiert wurde, in einer Datei mit UTF8 gespeichert und wenn er in einer Datei mit Shift-JIS gespeichert wird, unten angezeigt. Ich würde es gerne sehen.

Über die Zeichenkette von C..c


int main(void) {
    char str[] = "Ah"; //Wenn Sie ein Array gleichzeitig mit der Initialisierung deklarieren, können Sie die Anzahl der Elemente weglassen
    int size = sizeof(str);
    for (int i = 0; i < size; i++) {
        printf("%hhx ", str[i]); //Überprüfen Sie diese Ausgabe bei jeder Codierung
    }
}

Überprüfungsmethode:

  1. Öffnen Sie den Editor
  2. Ändern Sie die Editor-Codierungseinstellung in Shift-JIS oder UTF-8
  3. Fügen Sie den Quellcode ein und speichern Sie ihn
  4. Kompilieren Sie mit dem Clang-Compiler (\ $ cc file.c)
  5. Ausführen (\ $ ./a.out)

Ausgabe beim Speichern in UTF8:

case_utf8_result.txt


e3 81 82 0 

Ausgabe beim Speichern als Shift-JIS:

case_shift_jis_result.txt


82 a0 0

Geben Sie für jeden der oben genannten Werte auf dieser Site "A" ein und zeigen Sie das Ergebnis an. Ergebnis

Mit anderen Worten, Sie können sehen, dass das Ergebnis des Zeichenfolgenliterals des Mehrbytezeichens in der Sprache C mit der Codierung des Texteditors übereinstimmt.

Dies ist ein sehr natürliches Ergebnis, da wir die "Datei", in der der Quellcode geschrieben ist, an den Compiler übergeben, nicht den "Quellcode".

Mit anderen Worten, im Fall von UTF8 kann gesagt werden, dass "char str [] =" a "" die folgende Syntax für die Zuckerbeschichtung ist.

Über die Zeichenkette von C..c


int main(void) {
    //e3 81 82 0 
    char str[] = {0xe3, 0x81, 0x82, 0x0};
    printf("%s \n", str); //Wenn die Terminalcodierungseinstellung UTF8 ist, wird "A" angezeigt.
}

Wenn das oben auszuführende Terminal in UTF-8 codiert und ausgeführt wird, wird "A" angezeigt. Wenn Sie Shift-JIS verwenden, werden die Zeichen verstümmelt. (Einstellungen → Profile → Erweitertag) Screen Shot 2017-12-25 at 13.57.40.png

Infolgedessen ist oben das Ergebnis, wenn Shift-JIS festgelegt ist, und unten das Ergebnis, wenn UTF8 festgelegt ist. Screen Shot 2017-12-25 at 13.56.20.png

Zusammenfassung hier

Informationen zur Codierung, die beim Konvertieren in eine Swift-Zeichenfolge angegeben wurde

Ich möchte die unten stehende Swift-API verwenden, um die von der C-API übergebenen Zeichen in eine Swift-Zeichenfolge zu konvertieren. Wie sollte der zu diesem Zeitpunkt angegebene Codierungswert sein?

String.swift


init?(cString: UnsafePointer<CChar>, encoding enc: String.Encoding) //CChar = Int8

Der zu überprüfende C-Programmcode lautet wie folgt.

libc.c


char* file_name() {
    return "hello.txt";
}

char* new_file_header_str() {
    FILE *f = fopen(file_name(), "r");
    if (f == NULL) return NULL;

    char *str = calloc(256, sizeof(char));
    fgets(str, 256, f); //Nur eine Zeile
    fclose(f);
    return str;
}

Wenn Sie das Obige von Swift aus aufrufen, wird der Typ C char * als Typ UnsafeMutablePointer <Int8> übergeben.

Zunächst möchte ich überprüfen, ob das von der Funktion file_name erhaltene C-Zeichen in das Swift-Zeichen konvertiert wurde. Dieses Zeichenkettenliteral wird unverändert zurückgegeben. Mit anderen Worten, Sie können sehen, dass der Codierungswert beim Konvertieren in eine Swift-Zeichenfolge mit der Codierung in der libc.c-Datei übereinstimmen muss.

Was ist als nächstes mit dem Codierungswert, der zum Konvertieren des von der Funktion new_file_header_str erhaltenen C-Zeichens in eine Swift-Zeichenfolge verwendet wird? Hier wird die Zeichenfolge der Datei "hello.txt" zurückgegeben. Sie können also sehen, dass der Codierungswert, den Sie hier angeben müssen, mit dem Codierungswert übereinstimmen muss, in dem die Datei "hello.txt" gespeichert ist.

Unten finden Sie einen Beispielquellcode, der die Datei lib.c in UTF-8 und die Datei hello.txt in Shift-JIS speichert und jede Funktion von Swift aus aufruft.

get_str_from_c.swift


let name = file_name() //Optional<UnsafeMutablePointer<Int8>>
if let name = name,
    let converted = String(cString: name, encoding: .utf8) {
    print(converted)
} 

let header = new_file_header_str() //Optional<UnsafeMutablePointer<Int8>>
if let header = header,
    let converted = String(cString: header, encoding: .shiftJIS) {
    print(converted)
}

Informationen zum Aufrufen der C-Bibliothek finden Sie im Folgenden. https://qiita.com/ysn551/items/83e06cf74ae628cb573c

Zusammenfassung hier

Python3-String-Literal

Auf diese Weise speichert das C-String-Literal den Codierungswert direkt, sodass er von der Entwicklungsumgebung abhängt. Im Falle des Swift-Compilers können übrigens nur UTF8-Dateien kompiliert werden.

In Python3 ist der vom Zeichenfolgenliteral generierte Wert eine Zahl, dies ist jedoch ein Unicode-Wert. Daher muss beim Austausch von Zeichenfolgenliteralen zwischen Dateien keine Codierung berücksichtigt werden.

Das Überprüfungsergebnis mit python3 lautet wie folgt. Python2 verwendet übrigens Codierungswerte, daher ist es nutzlos, wenn die Codierung zwischen den Quellcodes unterschiedlich ist.

Speichern Sie die folgende Datei shift_jis.py in Shift-JIS-Codierung

shift_jis.py


#! coding=shift-jis

word = "Freut mich, dich kennenzulernen"

Speichern Sie die folgende Datei utf8.py als UTF8 und führen Sie sie aus.

utf8.py


#! coding=utf-8

import shift_jis as sh

if sh.word == "Freut mich, dich kennenzulernen": 
    print("true")
else:
    print("false")

Wenn ich das oben genannte auf python3 ausführe, wird true angezeigt, aber auf python2 wird false angezeigt.

Abschließende Zusammenfassung

Ich freue mich darauf, 2018 mit Ihnen zusammenzuarbeiten. m (__) m

Recommended Posts

Einführung in Zeichen und Zeichenfolgen in C-Sprache für Swift Programmer
C-Makro für watchOS und Swift API Availability
C-Makro für die Verfügbarkeit von tvOS und Swift API
Behandeln Sie Swift-Funktionen und -Verschlüsse als Zeiger für C-Sprachfunktionen
Erstellen Sie UnsafeMutablePointer <UnsafeMutablePointer <Int8>?>! In Swift für C char ** hoge
[Swift] Verwenden Sie diese Option für wo und nicht für und wenn