Die Geschichte der Portierung von Code von C nach Go (und zur Sprachspezifikation)

Hintergrund

Wir Programmierer portieren häufig Quellcode zwischen verschiedenen Sprachverarbeitungssystemen. Die Syntax wird vom Compiler garantiert, sodass ich nicht wirklich darauf eingehen kann.

Zur Auswertung in einer ähnlichen Syntax jedoch Die Bewertungsergebnisse können je nach Sprache unterschiedlich sein, und ich denke, dass ich manchmal süchtig danach bin.

Diesmal beim Portieren von C nach Go aufgrund unterschiedlicher Sprachspezifikationen Schreiben Sie eine Geschichte, die ein wenig süchtig macht, um das beabsichtigte Ergebnis zu erzielen.

"Gununu ... ich habe es auf die gleiche Weise transplantiert, egal wie ich es betrachtete ..."

Zum Beispiel dieser C-Code

main.c


// This is main.c

#include <stdio.h>

void main () {
    unsigned char  a;
    unsigned char  b;
    unsigned short c;

    a = 0x12;
    b = 0x34;
    c = 0x0000;

    c |= (unsigned short)(a << 8);
    c |= (unsigned short)(b << 0);

    printf("c is 0x%04X\n", c);
}

Ich habe es auf diesen Go-Code portiert.

main.go


package main

import "fmt"

func main() {
    var a uint8
    var b uint8
    var c uint16

    a = 0x12
    b = 0x34
    c = 0x0000;

    c |= uint16(a << 8)
    c |= uint16(b << 0)

    fmt.Printf("c is 0x%04X\n", c)
}

Dies ist eine übliche Prozedur zum Kombinieren der Bits zweier Variablen.

"Okay, ich habe die Besetzung von C auf die gleiche Weise geschrieben, Egal wie Sie es betrachten, es sollte mit genau dem gleichen Code funktionieren !! "

Ich habe es ausgeführt.

$ gcc -o main.exe main.c
$ main.exe
c is 0x1234
$ go build -o main.exe
$ main.exe
c is 0x0034

"Oh ... das Ausführungsergebnis ist anders ... ??"

"Die C-Quelle der Portierungsquelle hat die Besetzung richtig geschrieben. Go sollte wütend werden, wenn er überhaupt keinen Schimmel oder Gips hat ... Ich weiß nicht, ich weiß nicht ... "

Wenn Sie später darüber nachdenken, ist es nicht überraschend (obwohl es tatsächlich ein komplizierteres Programm war). Ich drehte meinen Hals damit ungefähr 30 Minuten lang.

"Hmm ... ?? Das ist ..."

Als ich meinen Kopf 30 Minuten lang verdreht habe (eigentlich habe ich verzweifelt debuggt) ...

"Oh, dies ist eine << 8" in C wurde auf int erweitert. " "Der Grund, warum C-Programme funktionieren, ist, dass ganzzahlige Operationen implizit auf int ... erweitert werden."

"Aber es gibt kein solches implizites Verhalten in Now Go ..."

main.c


    c |= (unsigned short)(a << 8);
    c |= (unsigned short)(b << 0);

Korrekt. C-Sprache ist der Hintergrund der Zeit, als die Sprache geboren wurde, Da das Sprachverarbeitungssystem ein CPU-abhängiger Standard ist, Führen Sie häufig "undefiniertes Verhalten", implizite Typumwandlung, Ganzzahlerweiterung usw. durch.

Schließlich ist der obige Code in Go ein schlechter Code. Ein kleiner Glaube hielt mich davon ab zu erkennen, warum Go's Code nicht funktionierte.

Das Problem ist also, dass Go explizit eine Typerweiterung wie diese schreiben musste:

main.go


    c |= uint16(a) << 8 //8bit Variable`<<`Geben Sie cast in eine 16-Bit-Variable ein, bevor die Operation ausgewertet wird
    c |= uint16(b) << 0

Die beiden Programme werden nun gleich bewertet.

$ gcc -o main.exe main.c
$ main.exe
c is 0x1234
$ go build -o main.exe
$ main.exe
c is 0x1234

Überprüfen Sie die Sprachspezifikationen

Bisher habe ich mich in meiner Erinnerung damit befasst. Was sind die Spezifikationen jeder Sprache überhaupt?

Diesmal werden die Sprachspezifikationen des Verarbeitungssystems (C, Go) tatsächlich verwendet Mal sehen, wie es definiert ist, sich zu verhalten, wenn diese Art der Verarbeitung durchgeführt wird.

C

Auf Folgendes wird aus ISO / IEC 9899 (Internationaler Standard der C-Sprache: C99), Shift, verwiesen Es ist eine Spezifikation der Berechnung.

#Über den Betrieb der Bitverschiebung
6.5.7 Bitwise shift operators
(Unterlassung)
Semantics
3 The integer promotions are performed on each of the operands. The type of the result is
that of the promoted left operand. If the value of the right operand is negative or is
greater than or equal to the width of the promoted left operand, the behavior is undefined.

(Übersetzt vom Autor)
Wenn der rechte Operand die Bitbreite des "erweiterten" linken Operanden überschreitet
Wenn der zweite Operand einen negativen Wert hat, ist das Verhalten undefiniert.

#Über die Ganzzahlerweiterung
If an int can represent all values of the original type, the value is converted to an int;
otherwise, it is converted to an unsigned int. These are called the integer
promotions.

(Übersetzt vom Autor)
Wenn int alle Werte des ursprünglichen Typs darstellen kann, wird der Wert in int konvertiert.
Andernfalls wird es in unsigned int konvertiert. Sie sind"integer promotion" (Ganzzahlige Erweiterung)Wird genannt.

Das Folgende ist die Spezifikation (Ganzzahlwertoperation) der Verschiebungsoperation, auf die in der Go-Referenz verwiesen wird.

Go

Integer overflow
For unsigned integer values, the operations +, -, *, and << are computed modulo 2n,
where n is the bit width of the unsigned integer's type. Loosely speaking,
these unsigned integer operations discard high bits upon overflow, and programs may rely on "wrap around".

(Übersetzt vom Autor)
(Unterlassung)Ganzzahlige Arithmetik ohne Vorzeichen schneidet die höherwertigen Bits ab und "wird umbrochen", wenn sie überlaufen.
(0xFF für 8-Bit-Ganzzahlen+ 0x01 =Dass es 0x00 sein wird)

Auch bei Schichtoperationen wird C implizit auf int erweitert, während Go hat kein implizites Verhalten und definiert das Verhalten klar.

Zusammenfassung

Go wird manchmal als besseres C bezeichnet, aber wie in diesem Beispiel ist das tatsächliche Verhalten auf Syntaxebene nicht explizit. In solchen Fällen, wenn das Primärdokument in einem leicht lesbaren Format bereitgestellt wird, Ich dachte, dass die Bezugnahme auf die Sprachspezifikationen zu einem schnellen, zuverlässigen und tieferen Verständnis der Sprachspezifikationen führen würde.

reference open-std.org ISO/IEC 9899:TC3 The Go Programming Language Specification

Recommended Posts

Die Geschichte der Portierung von Code von C nach Go (und zur Sprachspezifikation)
Eine Geschichte über die Portierung des Codes "Versuchen Sie zu verstehen, wie Linux funktioniert" nach Rust
Die Geschichte vom Umzug von Pipenv zur Poesie
Gehen Sie in die Sprache, um Teil 7 C in der Sprache GO zu sehen und sich daran zu erinnern
Ich habe versucht, die Zeit und die Zeit der C-Sprache zu veranschaulichen
Die Geschichte des Kopierens von Daten von S3 auf Googles TeamDrive
Immerhin die Geschichte der Rückkehr von Linux zu Windows
Gehen Sie zur Sprache, um Teil 8 zu sehen und sich daran zu erinnern. Rufen Sie die GO-Sprache von Python aus auf
Die Geschichte von Python und die Geschichte von NaN
Eine Geschichte über den Versuch, den Testprozess eines 20 Jahre alten Systems in C zu verbessern
Von der Einführung der GoogleCloudPlatform Natural Language API bis zur Verwendung
C-Sprache zum Sehen und Erinnern Teil 1 Rufen Sie die C-Sprache aus Python auf (Hallo Welt)
Ich habe versucht, die Phase der Geschichte mit COTOHA zu extrahieren und zu veranschaulichen
Versuchen Sie, Python-Code zu schreiben, um Go-Code zu generieren. - Versuchen Sie, JSON-to-Go usw. zu portieren
C-Sprache zum Anzeigen und Erinnern Teil 4 Rufen Sie die C-Sprache von Python (Argument) double auf
C-Sprache zum Anzeigen und Erinnern Teil 5 Rufen Sie die C-Sprache aus dem Python-Array (Argument) auf
Die Geschichte des Versuchs, den Client wieder zu verbinden
Die Geschichte, MeCab in Ubuntu 16.04 zu setzen
Portieren und Ändern des Doublet-Solvers von Python2 auf Python3.
Die Geschichte, deep3d auszuprobieren und zu verlieren
Die Geschichte von pep8 wechselt zu pycodestyle
So machen Sie VS Code auf die venv-Umgebung und ihre Vorteile aufmerksam
Versuchen Sie, das Programm "FORTRAN77 Numerical Computing Programming" auf C und Python zu portieren (Teil 1).
[C-Sprache] Achten Sie auf die Kombination aus Puffer-API und nicht pufferndem Systemaufruf
Versuchen Sie, das Programm "FORTRAN77 Numerical Computing Programming" auf C und Python zu portieren (Teil 3).
Versuchen Sie, das Programm "FORTRAN77 Numerical Computing Programming" auf C und Python zu portieren (Teil 2).
C-Sprache zum Sehen und Erinnern Teil 3 Rufen Sie die C-Sprache aus Python auf (Argument) c = a + b
Die Geschichte des Wechsels des Azure App Service-Websystems von Windows zu Linux
Die Geschichte, Sourcetrail × macOS × VS Code auszuprobieren
Liste des zu verschiebenden und zu merkenden Python-Codes
Ich möchte C ++ - Code aus Python-Code erstellen!
Von der Einführung von Pyethapp bis zur Vertragsabwicklung
So zeigen Sie das Änderungsdatum einer Datei in C-Sprache bis zu Nanosekunden an
Die Geschichte von Airflows Webserver und DAG, deren Laden lange dauert
Zusammenfassung von Anfang bis Kapitel 1 der Einführung in Entwurfsmuster, die in der Java-Sprache gelernt wurden
Extrahieren Sie Bilder und Tabellen mit Python aus PDF, um die Berichtslast zu verringern
Die Geschichte des Wechsels von WoSign zu Let's Encrypt für ein kostenloses SSL-Zertifikat
Der Operator und des Python-Bewertungsausdrucks scheint vom Ausdruck auf der linken Seite ausgewertet zu werden
Eine Geschichte über den Versuch, mit der kostenlosen Stufe von AWS zur COVID-19-Analyse beizutragen, und das Scheitern
So beschränken Sie die API, die in der gemeinsam genutzten Linux-Bibliothek in C-Sprache veröffentlicht werden soll
Die Geschichte des Starts eines Minecraft-Servers von Discord
Die Wand beim Ändern des Django-Dienstes von Python 2.7 auf Python 3-Serie
Die Geschichte von Python ohne Inkrement- und Dekrementoperatoren.
Der Prozess der Installation von Atom und der Ausführung von Python
[Von Zeit zu Zeit aktualisiert] Überprüfung von Let Code NumPy
Holen Sie sich den Rückkehrcode eines Python-Skripts von bat
Python zeigt aus der Perspektive eines C-Sprachprogrammierers
[C-Sprache] [Linux] Ruft den Wert der Umgebungsvariablen ab
Der erste Schritt, um Blender von Python verfügbar zu machen
Ich hatte das Gefühl, dass ich den Python-Code nach C ++ 98 portiert habe.
Die Geschichte der automatischen Sprachkonvertierung von TypeScript / JavaScript / Python
Die Geschichte, ein Ring-Fit-Abenteuer kaufen zu wollen
Die Geschichte der Verwendung von Circleci zum Bau vieler Linux-Räder
Ich bin gerade in Singapur. Eine Geschichte über das Erstellen eines LineBot und den Wunsch, einen unvergesslichen Job zu machen
[Linux] [C / C ++] So ermitteln Sie den Wert der Rücksprungadresse einer Funktion und den Funktionsnamen des Aufrufers
Ich möchte Importwarnungen von Pyright und pylint in VSCode entfernen
Scraping Gehen Sie zu EAT-Mitgliedsgeschäften in der Präfektur Osaka und konvertieren Sie zu CSV
Ich habe die Methode des maschinellen Lernens und ihre Implementierungssprache anhand der Tag-Informationen von Qiita betrachtet