C#, come molti linguaggi a tipizzazione statica, mette a disposizione diversi tipi che rappresentano numeri interi, ognuno con il proprio intervallo di valori. All'estremo inferiore, il tipo sbyte ha un valore minimo di -128 e un valore massimo di 127. Come per tutti i tipi interi, questi valori sono disponibili come <type>.MinValue e <type>.MaxValue. All'estremo superiore, il tipo long ha un valore minimo di -9.223.372.036.854.775.808 e un valore massimo di 9.223.372.036.854.775.807. Nel mezzo ci sono i tipi short e int.
Gli intervalli dipendono dall'ampiezza di memorizzazione che il sistema assegna al tipo. Ad esempio, un byte usa 8 bit e un long usa 64 bit.
Ognuno dei tipi precedenti è affiancato da un equivalente senza segno: sbyte/byte, short/ushort, int/uint e long/ulong. In tutti i casi l'intervallo dei valori va da 0 a due volte il massimo con segno negativo, più 1.
| Tipo | Ampiezza | Minimo | Massimo |
|---|---|---|---|
| sbyte | 8 bit | -128 | +127 |
| short | 16 bit | -32_768 | +32_767 |
| int | 32 bit | -2_147_483_648 | +2_147_483_647 |
| long | 64 bit | -9_223_372_036_854_775_808 | +9_223_372_036_854_775_807 |
| byte | 8 bit | 0 | +255 |
| ushort | 16 bit | 0 | +65_535 |
| uint | 32 bit | 0 | +4_294_967_295 |
| ulong | 64 bit | 0 | +18_446_744_073_709_551_615 |
Una variabile (o un'espressione) di un tipo può essere convertita facilmente in un altro tipo. Ad esempio, in un'operazione di assegnazione, se il tipo del valore che viene assegnato (lhs) garantisce che il valore rientri nell'intervallo del tipo a cui viene assegnato (rhs), allora basta una semplice assegnazione:
uint ui = uint.MaxValue;
ulong ul = ui; // no problem
Al contrario, se l'intervallo del tipo da cui si assegna non è un sottoinsieme dell'intervallo di valori del tipo di destinazione, serve un'operazione di cast, (), anche se il valore in questione rientra nell'intervallo di destinazione:
short s = 42;
uint ui = (uint)s;
La classe BitConverter offre un modo comodo per convertire i tipi interi da e verso array di byte.
Il lavoro sul progetto dell'auto radiocomandata continua. La larghezza di banda nel sistema di telemetria scarseggia e ti è stato chiesto di implementare un protocollo di messaggi per comunicare i dati di telemetria.
I dati vengono trasmessi in un buffer (un array di byte). Quando si inviano numeri interi, la dimensione del buffer viene ridotta applicando il protocollo descritto di seguito.
Ogni valore dovrebbe essere rappresentato con il tipo intero più piccolo possibile (i tipi byte e sbyte non sono inclusi, perché il risparmio sarebbe trascurabile):
| Da | A | Tipo |
|---|---|---|
| 4_294_967_296 | 9_223_372_036_854_775_807 | long |
| 2_147_483_648 | 4_294_967_295 | uint |
| 65_536 | 2_147_483_647 | int |
| 0 | 65_535 | ushort |
| -32_768 | -1 | short |
| -2_147_483_648 | -32_769 | int |
| -9_223_372_036_854_775_808 | -2_147_483_649 | long |
Il valore dovrebbe essere convertito nel numero di byte appropriato per il tipo assegnato. Il buffer completo comprende un byte che indica il numero di byte aggiuntivi nel buffer (byte di prefisso), seguito dai byte che contengono il numero intero (byte di payload).
Alcuni tipi usano lo stesso numero di byte (ad esempio i tipi uint e int). Normalmente avrebbero lo stesso byte di prefisso, ma questo renderebbe problematica la decodifica. Per ovviare a questo, il protocollo introduce un piccolo trucco: per i tipi con segno, il valore del loro byte di prefisso è 256 meno il numero di byte aggiuntivi nel buffer.
Nella comunicazione verranno inviati solo il byte di prefisso e il numero di byte successivi indicati dal prefisso. Internamente viene usato un buffer di 9 byte (con gli zeri finali, se necessario), sia dalle routine di invio che da quelle di ricezione.
Implementa il metodo statico TelemetryBuffer.ToBuffer() per codificare un buffer prendendo il parametro passato al metodo.
// Type: ushort, bytes: 2, signed: no, prefix byte: 2
TelemetryBuffer.ToBuffer(5)
// => {0x2, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
// Type: int, bytes: 4, signed: yes, prefix byte: 256 - 4
TelemetryBuffer.ToBuffer(Int32.MaxValue)
// => {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 };
Implementa il metodo statico TelemetryBuffer.FromBuffer() per decodificare il buffer ricevuto e restituire il valore sotto forma di long.
TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 })
// => 2147483647
Se il byte di prefisso ha un valore inatteso, allora dovrebbe essere restituito 0.
Iscriviti a Exercism per imparare e padroneggiare C# con 62 concetti178 esercizi e il mentoring di persone reali, tutto gratis.