O C#, tal como muitas linguagens de tipagem estática, disponibiliza vários tipos que representam números inteiros, cada um com o seu próprio intervalo de valores. No extremo inferior, o tipo sbyte tem um valor mínimo de -128 e um valor máximo de 127. Tal como em todos os tipos inteiros, estes valores estão disponíveis como <type>.MinValue e <type>.MaxValue. No extremo superior, o tipo long tem um valor mínimo de -9,223,372,036,854,775,808 e um valor máximo de 9,223,372,036,854,775,807. Entre os dois ficam os tipos short e int.
Os intervalos são determinados pela largura de armazenamento que o sistema atribui a cada tipo. Por exemplo, um byte usa 8 bits e um long usa 64 bits.
Cada um dos tipos acima tem um equivalente sem sinal: sbyte/byte, short/ushort, int/uint e long/ulong. Em todos os casos, o intervalo de valores vai de 0 até ao máximo negativo do tipo com sinal multiplicado por 2 e somado a 1.
| Type | Width | Minimum | Maximum |
|---|---|---|---|
| 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 |
Uma variável (ou expressão) de um tipo pode ser facilmente convertida noutro. Por exemplo, numa operação de atribuição, se o tipo do valor que está a ser atribuído (lhs) garantir que o valor fica dentro do intervalo do tipo a que se atribui (rhs), basta uma atribuição simples:
uint ui = uint.MaxValue;
ulong ul = ui; // no problem
Por outro lado, se o intervalo do tipo de origem não for um subconjunto do intervalo de valores do tipo de destino, é necessária uma operação de cast, (), mesmo que o valor em questão esteja dentro do intervalo do tipo de destino:
short s = 42;
uint ui = (uint)s;
A classe BitConverter oferece uma forma prática de converter tipos inteiros de e para arrays de bytes.
O trabalho no projeto do carro telecomandado continua. A largura de banda do sistema de telemetria é escassa e foi-te pedido que implementes um protocolo de mensagens para comunicar dados de telemetria.
Os dados são transmitidos num buffer (vetor de bytes). Quando se enviam números inteiros, o tamanho do buffer é reduzido através do protocolo descrito abaixo.
Cada valor deve ser representado no menor tipo inteiro possível (os tipos byte e sbyte não estão incluídos, pois a poupança seria trivial):
| De | Para | 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 |
O valor deve ser convertido no número de bytes adequado ao tipo que lhe for atribuído. O buffer completo é composto por um byte que indica o número de bytes adicionais no buffer (byte de prefixo), seguido dos bytes que contêm o número inteiro (bytes de carga útil).
Alguns dos tipos usam um número idêntico de bytes (por exemplo, os tipos uint e int). Normalmente, teriam o mesmo byte de prefixo, mas isso tornaria a descodificação problemática. Para contornar isto, o protocolo introduz um pequeno truque: nos tipos com sinal, o valor do byte de prefixo é 256 menos o número de bytes adicionais no buffer.
Na comunicação, só são enviados o byte de prefixo e o número de bytes seguintes indicado pelo prefixo. Internamente, é usado um buffer de 9 bytes (com zeros à direita, se necessário), tanto pelas rotinas de envio como pelas de receção.
Implementa o método estático TelemetryBuffer.ToBuffer() para codificar um buffer com o parâmetro passado ao método.
// 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 o método estático TelemetryBuffer.FromBuffer() para descodificar o buffer recebido e devolver o valor sob a forma de um long.
TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 })
// => 2147483647
Se o byte de prefixo tiver um valor inesperado, deve ser devolvido 0.
Inscreve-te no Exercism para aprenderes e dominares C# com 62 conceitos178 exercícios, e mentoria humana real, tudo grátis.