407 Stimmen

byte + byte = int... warum?

Betrachten Sie diesen C#-Code:

byte x = 1;
byte y = 2;
byte z = x + y; // ERROR: Cannot implicitly convert type 'int' to 'byte'

Das Ergebnis der Berechnungen, die an byte (oder short ) wird implizit in eine Ganzzahl zurückgewandelt. Die Lösung besteht darin, das Ergebnis explizit in ein Byte zurückzuwandeln:

byte z = (byte)(x + y); // this works

Ich frage mich nur, warum? Ist es architektonisch? Philosophisch?

Wir haben:

  • int + int = int
  • long + long = long
  • float + float = float
  • double + double = double

Warum also nicht?

  • byte + byte = byte
  • short + short = short ?

Ein wenig Hintergrundinformationen: Ich führe eine lange Liste von Berechnungen mit "kleinen Zahlen" (d.h. < 8) durch und speichere die Zwischenergebnisse in einem großen Array. Mit einer Byte-Array (anstelle eines int-Arrays) ist schneller (wegen der Cache-Treffer). Aber die umfangreichen Byte-Casts, die über den Code verteilt sind, machen ihn noch viel unleserlicher.

247voto

azheglov Punkte 5375

Die dritte Zeile Ihres Codeschnipsels:

byte z = x + y;

bedeutet eigentlich

byte z = (int) x + (int) y;

Es gibt also keine +-Operation auf Bytes, Bytes werden zunächst in Ganzzahlen umgewandelt und das Ergebnis der Addition zweier Ganzzahlen ist eine (32-Bit-)Ganzzahl.

186voto

Jon Skeet Punkte 1325502

In Bezug auf "warum es überhaupt passiert" es ist, weil es keine Operatoren von C # für Arithmetik mit Byte, sbyte, kurz oder ushort definiert, wie andere gesagt haben. Diese Antwort ist über por qué diese Operatoren sind nicht definiert.

Ich glaube, es geht im Wesentlichen um die Leistung. Prozessoren verfügen über native Operationen, um sehr schnell mit 32 Bit zu rechnen. Die Rückwandlung des Ergebnisses in ein Byte erfolgt automatisch könnte durchgeführt werden, würde aber zu Leistungseinbußen führen, wenn Sie dieses Verhalten nicht wünschen.

I piense en Dies wird in einem der kommentierten C#-Standards erwähnt. Suchen...

EDIT: Ärgerlicherweise habe ich mir jetzt die kommentierte ECMA C# 2-Spezifikation, die kommentierte MS C# 3-Spezifikation und die kommentierte CLI-Spezifikation angesehen, und keine Soweit ich sehen kann, wird dies in keinem von ihnen erwähnt. Ich bin sicher Ich habe den oben genannten Grund gesehen, aber ich weiß nicht mehr, wo. Entschuldigung, Referenz-Fans :(

70voto

Michael Petrotta Punkte 58361

I dachte Ich hatte das schon einmal irgendwo gesehen. Von dieser Artikel, The Old New Thing :

Angenommen, wir leben in einer Fantasiewelt in der Operationen mit 'Byte' zu Byte'.

byte b = 32;
byte c = 240;
int i = b + c; // what is i?

In dieser Fantasiewelt wird der Wert von i 16 sein! Warum? Weil die beiden Operanden des +-Operators sind beide Bytes sind, also wird die Summe "b+c" als ein Byte, was aufgrund eines Integer-Überlauf. (Und, wie ich bereits erwähnt habe ist der Integer-Überlauf der neue Sicherheitsangriffsvektor.)

EDIT : Raymond verteidigt im Wesentlichen den Ansatz, den C und C++ ursprünglich verfolgten. In den Kommentaren verteidigt er die Tatsache, dass C# den gleichen Ansatz verfolgt, mit dem Argument der Rückwärtskompatibilität der Sprache.

62voto

Alun Harford Punkte 3038

C#

ECMA-334 besagt, dass die Addition nur für int+int, uint+uint, long+long und ulong+ulong zulässig ist (ECMA-334 14.7.4). Daher sind dies die in Frage kommenden Operationen, die in Bezug auf 14.4.2 berücksichtigt werden müssen. Da es implizite Umwandlungen von Byte in int, uint, long und ulong gibt, sind alle Additionsfunktionselemente anwendbare Funktionselemente gemäß 14.4.2.1. Wir müssen den besten impliziten Cast nach den Regeln in 14.4.2.3 finden:

Casting(C1) nach int(T1) ist besser als casting(C2) nach uint(T2) oder ulong(T2), weil:

  • Wenn T1 int und T2 uint oder ulong ist, ist C1 die bessere Umwandlung.

Casting(C1) nach int(T1) ist besser als casting(C2) nach long(T2), weil es einen impliziten Cast von int nach long gibt:

  • Existiert eine implizite Konvertierung von T1 nach T2 und keine implizite Konvertierung von T2 nach T1, ist C1 die bessere Konvertierung.

Daher wird die Funktion int+int verwendet, die einen int zurückgibt.

Das ist ein langer Weg, um zu sagen, dass es sehr tief in der C#-Spezifikation begraben ist.

CLI

Die CLI arbeitet nur mit 6 Typen (int32, native int, int64, F, O und &) (ECMA-335 Teil 3 Abschnitt 1.5).

Byte (int8) gehört nicht zu diesen Typen und wird vor der Addition automatisch in einen int32 umgewandelt. (ECMA-335 Partition 3 Abschnitt 1.6)

29voto

Christopher Punkte 8508

Die Antworten, die auf eine gewisse Ineffizienz beim Addieren von Bytes und Abschneiden des Ergebnisses auf ein Byte hinweisen, sind falsch. x86-Prozessoren verfügen über Befehle, die speziell für Ganzzahloperationen auf 8-Bit-Mengen ausgelegt sind.

Bei x86/64-Prozessoren ist die Durchführung von 32-Bit- oder 16-Bit-Operationen aufgrund des zu dekodierenden Operanden-Präfix-Bytes sogar weniger effizient als 64-Bit- oder 8-Bit-Operationen. Auf 32-Bit-Maschinen hat die Durchführung von 16-Bit-Operationen den gleichen Nachteil, aber es gibt immer noch spezielle Opcodes für 8-Bit-Operationen.

Viele RISC-Architekturen verfügen über ähnliche wort-/byte-effiziente Befehle. Diejenigen, die dies nicht haben, verfügen im Allgemeinen über einen "store-and-convert-to-signed-value-of-some-bit-length".

Mit anderen Worten, diese Entscheidung muss auf der Vorstellung davon beruhen, wofür der Byte-Typ gedacht ist, und nicht auf den zugrundeliegenden Ineffizienzen der Hardware.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X