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.
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.
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
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.
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