sexta-feira, 2 de janeiro de 2015

Com quantos bits se faz um byte e com quantos bytes se faz um short int?

Um dos primeiros conceitos conhecidos pelo pessoal da Computação é que o bit (binary digit) é a unidade básica da informação digital correspondente a um único dígito binário (0 ou 1). Já o byte costuma ser definido como um grupo de oito bits, tradição iniciada com o IBM System 360. Este tamanho, no entanto até pode ser considerado um padrão de fato, mas não o é de direito. Vejam que o padrão IEEE 1541-2002 ("IEEE Standard for Prefixes for Binary Multiples") apenas define byte como sendo um grupo consecutivo de bits e chama de octeto o byte de 8 bits. Até onde sei, o padrão IEC 80000-13 ("Quantities and units -- Part 13: Information science and technology")  apenas recomenda que a quantidade de bits em um byte sejam oito.

No caso do C++, a especificação da linguagem define que byte é a unidade de armazenamento e terá tamanho suficiente (em bits consecutivos) para acomodar o conjunto de caracteres básicos do ambiente de execução e os 8 bits do UTF-8. Atendidos estes requisitos, cada implementação tem liberdade de definir o tamanho em bits de um byte. Ainda está previsto que o tamanho de um char, em bytes é 1 (ou seja, sizeof(char)==1). O Stroustrup, em "The C++ Programming Language" prefere descrever que o operador sizeof retorna a quantidade de chars ocupada por uma expressão ou tipo em vez de quantidade de bytes. Então, em se tratando de C++, não devemos assumir que um byte tenha 8 bits, embora este seja o caso mais comum.

O tamanho dos diversos tipos fundamentais


Não é incomum encontrarmos em materiais sobre a linguagem, até mesmo em alguns livros, tabelas especificando o tamanho em bits, ou em bytes, para os tipos de dados fundamentais da linguagem, como neste exemplo:



Em relação aos tipos inteiros, a linguagem apenas estabelece que cada um dos tipos signed char, short int, int, long int e long long int utilizam, no mínimo, o mesmo espaço de armazenamento do seu anterior nesta ordem. Ou seja, podemos resumir a regra a isto:

1 == sizeof(char) <= sizeof(short int) <= sizeof(int) <= sizeof(long int) <= sizeof(long long int)

Percebam que, embora isto seja incomum na prática, nada impede que um long long int, por exemplo, possua o mesmo tamanho, em bytes, de um short int e portanto, o mesmo intervalo de armazenamento.

Ao declararmos uma variável apenas como int, ela terá, normalmente o tamanho da palavra de máquina para aquela arquitetura e irá oferecer a aritmética mais eficiente disponível para inteiros.

Quanto aos tipos em ponto-flutuante a linguagem estabelece que existem três tipos: float, double e long double. Cada um destes, na ordem apresentada, oferece, no mínimo, a precisão do antecessor. Geralmente as implementações seguem o padrão IEEE 754-1985, e utilizam 32 bits para os números em precisão simples e 64 bits para a precisão dupla. Já a precisão extendida (long double), não é um tamanho padronizado, correspondendo, na arquitetura x86 ao formato extendido de 80 bits.

Verifique o tamanho de cada tipo em seu compilador com o código a seguir [disponível no Ideone]:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    #include <iostream>
    using namespace std;
     
    int main() {
        cout << "signed char: " << sizeof(signed char) << endl;
        cout << "short int: " << sizeof(short int) << endl;
        cout << "int: " << sizeof(int) << endl;
        cout << "long int: " << sizeof(long int) << endl;
        cout << "long long int: " << sizeof(long long int) << endl;
     
        cout << "float: " << sizeof(float) << endl;
        cout << "double: " << sizeof(double) << endl;
        cout << "long double: " << sizeof(long double) << endl;
        return 0;
    }

Os tamanhos exatos em <cstdint>


Se precisarmos de tipos inteiros de tamanho determinado, podemos recorrer ao #include<cstdint>. Estão previstos tipos inteiros com ou sem sinal para os tamanhos de 8, 16, 32 e 64 bits, como segue:

// Com sinal
int8_t
int16_t
int32_t
int64_t
// Sem sinal
uint8_t
uint16_t
uint32_t
uint64_t

 
O padrão da linguagem, no entanto, define que estes tipos são opcionais naquele header. Ou seja, se a implementação em questão não puder oferecer algum destes tamanhos, ela pode omiti-lo, o que causaria erro de compilação nos programas que os usam.

O emprego sem critérios destes tipos podem reduzir, portanto, a portabilidade do código, o que se opõem ao objetivo de criação deste include. Devemos usa-los com precaução, apenas nos casos em que se quer a garantia de tamanho para uma determinada variável ou campo de struct ou class. Exemplos de aplicação seria onde a interface com outros dispositivos ou aplicações ocorrem em binário, como geração de arquivos binários que serão lidos por outros aplicativos ou na construção de devices drivers.

Nenhum comentário:

Postar um comentário