2012-05-13 11 views
10

ero un guardare il codice sorgente di a project, e ho notato il seguente statement (sia keyByte e codedByte sono di tipo byte):C#: Il risultato di lanciare un numero intero negativo a un byte

return (byte)(keyByte - codedByte); 

Sto cercando ora di capire quale sarebbe il risultato nei casi in cui keyByte è più piccolo di codedByte, che si traduce in un numero intero negativo.

Dopo alcuni esperimenti per capire il risultato di lanciare un intero negativo che ha un valore nella gamma [-255: -1], ho ottenuto i seguenti risultati:

byte result = (byte) (-6); // result = 250 
byte result = (byte) (-50); // result = 206 
byte result = (byte) (-17); // result = 239 
byte result = (byte) (-20); // result = 236 

Così, a condizione che -256 < a < 0, sono stato in grado di determinare il risultato:

result = 256 + a; 

la mia domanda è: devo sempre aspettare che questo sia il caso?

+0

ripetere: hai assolutamente ragione. Poiché qualsiasi valore "negativo" è al di fuori del dominio di un "byte" .Net, prima Net promuove (con un valore integrale maggiore di 255). – paulsm4

risposta

4

Sì, sarà sempre così (ovvero non dipende semplicemente dall'ambiente o dal compilatore, ma è definito come parte delle specifiche del linguaggio C#). Vedere http://msdn.microsoft.com/en-us/library/aa691349(v=vs.71).aspx:

In un unchecked contesto, il risultato viene troncato scartando tutti i bit di ordine superiore che non rientrano nel tipo di destinazione.

La prossima domanda è, se si toglie i bit di ordine superiore di un negativo int tra -256 e -1, e leggere come un byte, che cosa si ottiene? Questo è ciò che hai già scoperto attraverso la sperimentazione: è 256 + x.

Nota che endianness non ha importanza perché stiamo scartando i bit di ordine elevato (o più significativi), non i "primi" 24 bit. Quindi, indipendentemente da quale fine abbiamo preso, ci rimane il byte meno significativo che ha creato quell'int.

+0

Per curiosità, cosa succede se il tuo hardware (CPU) utilizza qualcosa di diverso da una rappresentazione binaria complementare di interi? Per ottenere una risposta a questo dobbiamo andare alle specifiche CLR piuttosto che alle specifiche C#. ECMA335, Sezione 12.1, identifica 'int' come" valore firmato a complemento a due bit a 32 bit ". Questo è tutto solo teoria con la gamma limitata di hardware su cui è attualmente eseguito .NET (o mono), ma è la risposta definitiva alla domanda che ci è stata posta. Sì, i valori negativi non possono dare risultati numericamente diversi, nemmeno su ipotetici hardware futuri. –

+0

Per curiosità, cosa succederebbe se i dinosauri non si estinguessero mai? Vogliamo pterodattili invece di inventare aerei a reazione? Perché non dare solo credito a Mota per il semplice fatto che questo è assolutamente e totalmente corretto: 'per qualsiasi linguaggio .Net, per i valori integrali firmati -256 paulsm4

+0

Un altro riferimento per il nonce : [Esiste una conversione implicita predefinita da byte a breve, ushort, int, uint, long, ulong, float, double o decimal.] (Http://msdn.microsoft.com/en-us/library/5bdb6693% 28v = vs.71% 29.aspx) – paulsm4

4

Sì. Ricordate, non c'è una cosa come "-" nel dominio di un Net "Byte":

http://msdn.microsoft.com/en-us/library/e2ayt412.aspx

Perché Byte è un tipo senza segno, non può rappresentare un negativo numero. Se si utilizza l'operatore unario meno (-) su un'espressione che valuta per digitare Byte, Visual Basic converte prima l'espressione in Breve . (Nota: sostituire qualsiasi CLR/linguaggio .NET per "Visual Basic")

APPENDICE: Ecco un'applicazione di esempio:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace TestByte 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      for (int i = -255; i < 256; i++) 
      { 
       byte b = (byte)i; 
       System.Console.WriteLine("i={0}, b={1}", i, b); 
      } 
     } 
    } 
} 

Ed ecco l'output risultante:

testbyte|more 
i=-255, b=1 
i=-254, b=2 
i=-253, b=3 
i=-252, b=4 
i=-251, b=5 
... 
i=-2, b=254 
i=-1, b=255 
i=0, b=0 
i=1, b=1 
... 
i=254, b=254 
i=255, b=255 
+1

L'ho downvoted perché non affronta la sua preoccupazione - vale a dire, se la trasmissione di un numero intero negativo a byte sarà sempre la stessa. È bello sapere, ma completamente separato, che se si dice '-b', dove' b' è un 'byte', lo convertirà in un' short' prima. –

+0

Puoi dare un riferimento? ECMA 334 (14.7) sembra riconoscere solo aritmetica su 'int',' uint', 'lungo',' ulong'. Non che sia molto rilevante qui, ma uno di noi ha torto nei dettagli e sono curioso di sapere chi sia. –

+0

Non ho idea di cosa faccia Visual Basic, ma non è quello che dice la specifica C# nella sezione 4.5.1: "Per l'operatore unario, l'operando viene convertito in tipo T, dove T è il primo di int e lungo che può rappresentare pienamente tutti i valori possibili dell'operando. " In questo caso quel tipo è int. Inoltre, binary - converte in int anche per byte. –

0

Questo è ciò che accade nel contesto unchecked. Si potrebbe dire che il runtime (o il compilatore se lo-è noto per il cast di Byte) compila o sottrae 256 volte quante volte è necessario finché non trova un valore rappresentabile.

In un contesto checked, un risultato di eccezione (o errore compiletime). Vedi http://msdn.microsoft.com/en-us/library/khy08726.aspx

0

Sì, a meno che non si ottenga un'eccezione.

.NET definisce tutte le operazioni aritmetiche solo su tipi di dati di 4 byte e più grandi. Quindi l'unico punto non ovvio è come la conversione di un int in un byte funziona.

Per una conversione da un tipo integrale a un altro tipo integrale, il risultato della conversione dipende dal contesto di controllo di overflow (si afferma lo standard ECMA 334, Sezione 13.2.1).

Così, nel seguente contesto

checked 
{ 
    return (byte)(keyByte - codedByte); 
} 

si vedrà un System.OverflowException.Mentre nel seguente contesto:

unchecked 
{ 
    return (byte)(keyByte - codedByte); 
} 

si sono garantiti a vedere sempre i risultati che ci si aspetta, indipendentemente dal fatto che si fa o non si aggiunge un multiplo di 256 alla differenza; ad esempio, 2 - 255 = 3.

Questo è vero indipendentemente da come l'hardware represents signed values. Lo standard CLR (ECMA 335) specifica, nella Sezione 12.1, che il tipo Int32 è un "valore firmato a complemento a due bit a 32 bit". (Beh, questo corrisponde anche a tutte le piattaforme su cui .NET o mono sono attualmente disponibili comunque, quindi si potrebbe quasi pensare che funzionerebbe comunque, ma è bene sapere che la pratica è supportata dallo standard di linguaggio e portatile.)

Alcuni team non desiderano specificare esplicitamente i contesti di controllo di overflow, poiché hanno una politica di controllo degli overflow nelle prime fasi del ciclo di sviluppo, ma non nel codice rilasciato. In questi casi si può tranquillamente fare byte aritmetica in questo modo:

return (byte)((keyByte - codedByte) % 256); 
3

Ecco un algoritmo che esegue la stessa logica fusione al byte, per aiutarvi a capire che:

Per positivi:

byte bNum = iNum % 256; 

per i negativi:

byte bNum = 256 + (iNum % 256); 

E 'come la ricerca di qualsiasi 0.123.748,322 milache causa l'intervallo x + 255k nell'intervallo 0 ... 255. Potrebbe esserci solo uno k che produce un risultato con quell'intervallo e il risultato sarà il risultato del cast in byte.

Un altro modo di vedere le cose è come se "cicli in tutto il campo di valori di byte":

Consente di utilizzare il iNum = -712 di nuovo, e definire un bNum = 0.

Faremo iNum++; bNum--; fino iNum == 0:

iNum = -712; 
bNum = 0; 

iNum++; // -711 
bNum--; // 255 (cycles to the maximum value) 

iNum++; // -710 
bNum--; // 254 

... // And so on, as if the iNum value is being *consumed* within the byte value range cycle. 

Questa è, ovviamente, solo un esempio per vedere come logicamente funziona.

Problemi correlati