Basicamente, todo computador moderno é uma máquina que empurra pouco. Geralmente ele empurra bits em grupos de dados, chamados bytes, palavras, dwords ou qwords.
Um byte consiste em 8 bits, uma palavra 2 bytes (ou 16 bits), uma palavra dword 2 (ou 32 bits) e uma palavra qword 2 dwords (ou 64 bits). Essa não é a única maneira de organizar bits. A manipulação de 128 e 256 bits também ocorre, geralmente nas instruções do SIMD.
As instruções de montagem operam nos registradores e os endereços de memória geralmente operam em uma das formas acima.
A ALU (unidades lógicas aritméticas) opera em pacotes de bits como se representassem números inteiros (geralmente no formato Complemento de Dois) e FPUs como se estivessem em valores de ponto flutuante (geralmente no estilo IEEE 754 float
e double
). Outras partes agirão como se fossem dados agrupados de algum formato, caracteres, entradas da tabela, instruções da CPU ou endereços.
Em um computador típico de 64 bits, pacotes de 8 bytes (64 bits) são endereços. Exibimos esses endereços convencionalmente como em um formato hexadecimal (como 0xabcd1234cdef5678
), mas essa é apenas uma maneira fácil para os humanos lerem os padrões de bits. Cada byte (8 bits) é escrito como dois caracteres hexadecimais (equivalentemente, cada caractere hexadecimal - 0 a F - representa 4 bits).
O que realmente está acontecendo (para alguns níveis) é que existem bits, geralmente armazenados em um registro ou armazenados em locais adjacentes em um banco de memória, e estamos apenas tentando descrevê-los para outro ser humano.
Seguir um ponteiro consiste em pedir ao controlador de memória que nos forneça alguns dados nesse local. Você normalmente solicita ao controlador de memória um certo número de bytes em um determinado local (bem, implicitamente, um intervalo de locais, geralmente contíguo), e ele é entregue através de vários mecanismos nos quais não vou entrar.
O código geralmente especifica um destino para os dados a serem buscados - um registro, outro endereço de memória etc. - e geralmente é uma má idéia carregar dados de ponto flutuante em um registro esperando um número inteiro ou vice-versa.
O tipo de dados em C / C ++ é algo que o compilador controla e altera o código gerado. Geralmente, não há nada intrínseco nos dados que os torne realmente de qualquer tipo. Apenas uma coleção de bits (organizados em bytes) que são manipulados como um número inteiro (ou como um flutuador ou como um endereço) pelo código.
Há exceções para isto. Existem arquiteturas em que certas coisas são de tipos diferentes de bits. O exemplo mais comum são as páginas de execução protegidas - enquanto as instruções informando à CPU o que fazem são bits, no tempo de execução, as páginas (de memória) contendo o código a ser executado são marcadas especialmente, não podem ser modificadas e você não pode executar páginas que não estão marcadas. como páginas de execução.
Também existem dados somente leitura (às vezes armazenados na ROM que não podem ser gravados fisicamente!), Problemas de alinhamento (alguns processadores não podem carregar double
s da memória, a menos que estejam alinhados de maneiras particulares, ou instruções SIMD que exijam certo alinhamento) e inúmeras outras peculiaridades da arquitetura.
Até o nível de detalhe acima é uma mentira. Os computadores não estão "realmente" pressionando bits, estão pressionando tensões e correntes. Essas tensões e correntes às vezes não fazem o que "deveriam" fazer no nível de abstração dos bits. Os chips são projetados para detectar a maioria desses erros e corrigi-los sem que a abstração de nível superior precise estar ciente disso.
Até isso é mentira.
Cada nível de abstração oculta o nível abaixo e permite que você pense em resolver problemas sem ter que se lembrar dos diagramas de Feynman para imprimir "Hello World"
.
Portanto, com um nível suficiente de honestidade, os computadores pressionam os bits, e esses bits recebem significado pela maneira como são usados.