Para abordar a pergunta que você postou em vários comentários (que eu acho que você deve editar em sua postagem):
O que não entendo é como o computador sabe quando lê o valor e o endereço de uma variável, como 10001, se for int ou char. Imagine clicar em um programa chamado anyprog.exe. Imediatamente o código começa a executar. Este arquivo exe inclui informações sobre se as variáveis são armazenadas como em ou char?
Então, vamos colocar algum código nele. Digamos que você escreva:
int x = 4;
E vamos supor que ele seja armazenado na RAM:
0x00010004: 0x00000004
A primeira parte é o endereço, a segunda parte é o valor. Quando seu programa (que é executado como código de máquina) é executado, tudo o que vê 0x00010004
é o valor 0x000000004
. Ele não 'sabe' o tipo desses dados e não sabe como eles devem ser usados.
Então, como o seu programa descobre a coisa certa a fazer? Considere este código:
int x = 4;
x = x + 5;
Temos uma leitura e uma gravação aqui. Quando seu programa lê x
da memória, ele fica 0x00000004
lá. E seu programa sabe adicionar 0x00000005
a ele. E a razão pela qual seu programa 'sabe' que essa é uma operação válida é porque o compilador garante que a operação seja válida por meio de segurança de tipo. Seu compilador já verificou que você pode adicionar 4
e 5
juntar. Portanto, quando seu código binário é executado (o exe), ele não precisa fazer essa verificação. Ele apenas executa cada etapa às cegas, assumindo que tudo está OK (coisas ruins acontecem quando na verdade, não estão OK).
Outra maneira de pensar sobre isso é assim. Eu lhe dou esta informação:
0x00000004: 0x12345678
Mesmo formato de antes - endereço à esquerda, valor à direita. Que tipo é o valor? Neste ponto, você conhece tanta informação sobre esse valor quanto o seu computador quando está executando o código. Se eu lhe dissesse para adicionar 12743 a esse valor, você poderia fazê-lo. Você não tem idéia de quais serão as repercussões dessa operação em todo o sistema, mas adicionar dois números é algo em que você é realmente bom, para que possa fazê-lo. Isso torna o valor um int
? Não necessariamente - tudo o que você vê são dois valores de 32 bits e o operador de adição.
Talvez um pouco da confusão esteja voltando aos dados. Se tiver-mos:
char A = 'a';
Como o computador sabe exibir a
no console? Bem, existem muitos passos para isso. O primeiro é ir para A
o local s na memória e lê-lo:
0x00000004: 0x00000061
O valor hexadecimal a
em ASCII é 0x61, portanto, o acima pode ser algo que você veria na memória. Então agora nosso código de máquina conhece o valor inteiro. Como ele sabe transformar o valor inteiro em um caractere para exibi-lo? Simplificando, o compilador certificou-se de executar todas as etapas necessárias para fazer essa transição. Mas o seu próprio computador (ou o programa / exe) não tem idéia de qual é o tipo desses dados. Esse valor de 32 bits pode ser qualquer coisa - int
, char
metade de um double
, um ponteiro, parte de uma matriz, parte de a string
, parte de uma instrução, etc.
Aqui está uma breve interação que seu programa (exe) pode ter com o computador / sistema operacional.
Programa: Eu quero iniciar. Eu preciso de 20 MB de memória.
Sistema operacional: encontra 20 MB de memória livre que não estão em uso e os entrega
(A nota importante é que este poderia voltar quaisquer 20 MB livres de memória, eles nem sequer tem que ser contíguos. Neste ponto, o programa pode agora operar dentro da memória que ele tem sem falar com o OS)
Programa: Vou assumir que o primeiro ponto na memória é uma variável inteira de 32 bits x
.
(O compilador garante que o acesso a outras variáveis nunca toque esse ponto na memória. Não há nada no sistema que diga que o primeiro byte é variável x
ou que a variável x
é um número inteiro. Uma analogia: você tem um saco. Você diz às pessoas que você só colocará bolas de cor amarela nessa sacola. Quando alguém mais tarde puxar algo da sacola, seria chocante que puxasse algo azul ou um cubo - algo deu terrivelmente errado. O mesmo vale para computadores: o seu Agora, o programa está assumindo que o primeiro ponto de memória é variável xe que é um número inteiro.Se algo mais for escrito sobre esse byte de memória ou se for considerado algo mais - algo horrível aconteceu. O compilador garante que esse tipo de coisa não seja acontecer)
Programa: Agora vou escrever 2
nos quatro primeiros bytes em que suponho que x
esteja.
Programa: quero adicionar 5 a x
.
Lê o valor de X em um registro temporário
Adiciona 5 ao registro temporário
Armazena o valor do registro temporário de volta no primeiro byte, que ainda é assumido x
.
Programa: Vou assumir que o próximo byte disponível é a variável char y
.
Programa: Escreverei a
para a variável y
.
Programa: quero exibir o conteúdo de y
Lê o valor no segundo ponto de memória
Usa uma biblioteca para converter do byte para um caractere
Utiliza bibliotecas gráficas para alterar a tela do console (definindo pixels de preto para branco, rolando uma linha etc.)
(E continua a partir daqui)
O que você provavelmente está se incomodando é - o que acontece quando o primeiro lugar na memória não é mais x
? ou o segundo não é mais y
? O que acontece quando alguém lê x
como um char
ou y
como um ponteiro? Em suma, coisas ruins acontecem. Algumas dessas coisas têm um comportamento bem definido, e algumas têm um comportamento indefinido. O comportamento indefinido é exatamente isso - tudo pode acontecer, do nada, até travar o programa ou o sistema operacional. Mesmo um comportamento bem definido pode ser malicioso. Se eu posso mudar x
para um ponteiro para o meu programa e fazer com que seu programa o use como ponteiro, posso fazer com que seu programa comece a executar o meu programa - que é exatamente o que os hackers fazem. O compilador está lá para ajudar a garantir que não usamos int x
como umstring
e coisas dessa natureza. O código da máquina em si não está ciente dos tipos e fará apenas o que as instruções dizem. Também há uma grande quantidade de informações descobertas em tempo de execução: quais bytes de memória o programa pode usar? Será que x
começam no primeiro byte ou dia 12?
Mas você pode imaginar o quão horrível seria realmente escrever programas como este (e você pode, na linguagem assembly). Você começa 'declarando' suas variáveis - diz a si mesmo que o byte 1 é x
, o byte 2 é y
e, ao escrever cada linha de código, carregando e armazenando registros, você (como humano) precisa se lembrar qual é x
e qual uma é y
porque o sistema não tem ideia. E você (como humano) precisa se lembrar de que tipos x
e quais y
são, porque mais uma vez - o sistema não tem idéia.