Per rispondere alla domanda che hai pubblicato in diversi commenti (che penso che dovresti modificare nel tuo post):
Quello che non capisco è come fa il computer a sapere quando legge il valore di una variabile e l'indirizzo come 10001 se è un int o char. Immagina di fare clic su un programma chiamato anyprog.exe. Immediatamente inizia l'esecuzione del codice. Questo file exe include informazioni su se le variabili sono memorizzate come in o char?
Quindi mettiamoci un po 'di codice. Diciamo che scrivi:
int x = 4;
E supponiamo che venga memorizzato nella RAM:
0x00010004: 0x00000004
La prima parte è l'indirizzo, la seconda parte è il valore. Quando il tuo programma (che viene eseguito come codice macchina) viene eseguito, tutto ciò che vede 0x00010004
è il valore 0x000000004
. Non "conosce" il tipo di questi dati e non sa come si debba "utilizzare".
Quindi, come fa il tuo programma a capire la cosa giusta da fare? Considera questo codice:
int x = 4;
x = x + 5;
Abbiamo una lettura e una scrittura qui. Quando il tuo programma legge x
dalla memoria, trova 0x00000004
lì. E il tuo programma sa aggiungere 0x00000005
ad esso. E il motivo per cui il tuo programma "sa" che si tratta di un'operazione valida, è perché il compilatore garantisce che l'operazione sia valida attraverso la sicurezza del tipo. Il compilatore ha già verificato che è possibile aggiungere 4
e 5
insieme. Quindi quando viene eseguito il codice binario (exe), non è necessario effettuare tale verifica. Esegue semplicemente ogni passaggio alla cieca, supponendo che tutto sia OK (le cose brutte accadono quando in realtà non sono OK).
Un altro modo di pensarci è così. Ti do queste informazioni:
0x00000004: 0x12345678
Stesso formato di prima: indirizzo a sinistra, valore a destra. Di che tipo è il valore? A questo punto, conosci quante più informazioni su quel valore come il tuo computer quando esegue il codice. Se ti dicessi di aggiungere 12743 a quel valore, potresti farlo. Non hai idea di quello che le ripercussioni di tale operazione saranno in tutto il sistema, ma l'aggiunta di due numeri è qualcosa che sei veramente bravo, così si potrebbe farlo. Questo rende un valore un int
? Non necessariamente: tutto ciò che vedi sono due valori a 32 bit e l'operatore addizione.
Forse un po 'di confusione sta quindi recuperando i dati. Se abbiamo:
char A = 'a';
Come fa il computer a essere visualizzato a
nella console? Bene, ci sono molti passaggi per farlo. Il primo è andare nella A
posizione in memoria e leggerlo:
0x00000004: 0x00000061
Il valore esadecimale per a
in ASCII è 0x61, quindi quanto sopra potrebbe essere qualcosa che vedresti in memoria. Quindi ora il nostro codice macchina conosce il valore intero. Come fa a sapere di trasformare il valore intero in un carattere per visualizzarlo? In poche parole, il compilatore si è assicurato di inserire tutti i passaggi necessari per effettuare tale transizione. Ma il tuo stesso computer (o il programma / exe) non ha idea di quale sia il tipo di tali dati. Quel valore a 32 bit potrebbe essere qualsiasi cosa - int
, char
metà di un double
puntatore, parte di un array, parte di un string
, parte di un'istruzione, ecc.
Ecco una breve interazione che il tuo programma (exe) potrebbe avere con il computer / sistema operativo.
Programma: voglio iniziare. Ho bisogno di 20 MB di memoria.
Sistema operativo: trova 20 MB di memoria libera che non sono in uso e li consegna
(La nota importante è che questa potrebbe tornare ogni 20 MB liberi della memoria, che non hanno nemmeno bisogno di essere contigui. A questo punto, il programma può ora operare all'interno della memoria che ha senza parlare con il sistema operativo)
Programma: suppongo che il primo punto in memoria sia una variabile intera a 32 bit x
.
(Il compilatore si assicura che gli accessi ad altre variabili non tocchino mai questo punto in memoria. Non c'è nulla nel sistema che dice che il primo byte è variabile x
o che la variabile x
è un numero intero. Un'analogia: hai una borsa. Dici alla gente che metterai solo palline di colore giallo in questa borsa. Quando in seguito qualcuno estrae qualcosa dalla borsa, sarebbe scioccante che tirasse fuori qualcosa di blu o un cubo - qualcosa è andato terribilmente storto. Lo stesso vale per i computer: il tuo il programma ora sta assumendo che il primo punto di memoria sia la variabile x e che sia un numero intero. Se qualcos'altro viene mai scritto su questo byte di memoria o si presume che sia qualcos'altro - è successo qualcosa di orribile. Il compilatore assicura che questo tipo di cose don non succede)
Programma: ora scriverò 2
sui primi quattro byte in cui suppongo x
sia.
Programma: voglio aggiungere 5 a x
.
Legge il valore di X in un registro temporaneo
Aggiunge 5 al registro temporaneo
Memorizza il valore del registro temporaneo nel primo byte, che si presume sia ancora x
.
Programma: suppongo che il prossimo byte disponibile sia la variabile char y
.
Programma: scriverò a
su variabile y
.
Programma: Voglio visualizzare il contenuto di y
Legge il valore nel secondo punto di memoria
Utilizza una libreria per convertire da byte a un carattere
Utilizza librerie grafiche per modificare la schermata della console (impostazione dei pixel da nero a bianco, scorrimento di una riga, ecc.)
(E continua da qui)
Ciò su cui probabilmente ti stai impiccando è: cosa succede quando il primo punto in memoria non è più x
? o il secondo non è più y
? Cosa succede quando qualcuno legge x
come char
o y
come puntatore? In breve, succedono cose brutte. Alcune di queste cose hanno un comportamento ben definito e alcune hanno un comportamento indefinito. Il comportamento indefinito è esattamente questo: tutto può succedere, dal nulla, al crash del programma o del sistema operativo. Anche un comportamento ben definito può essere dannoso. Se posso passare x
a un puntatore al mio programma e far sì che il tuo programma lo utilizzi come puntatore, allora posso fare in modo che il tuo programma inizi a eseguire il mio programma, che è esattamente ciò che fanno gli hacker. Il compilatore è lì per aiutare a assicurarsi che non usiamo int x
comestring
e cose di quella natura. Il codice macchina stesso non è a conoscenza dei tipi e farà solo ciò che le istruzioni gli dicono di fare. Esiste anche una grande quantità di informazioni scoperte in fase di esecuzione: quali byte di memoria è autorizzato a utilizzare il programma? Non x
ha inizio dal primo byte o il 12?
Ma puoi immaginare quanto sarebbe orribile scrivere programmi come questo (e puoi, nel linguaggio assembly). Cominci 'dichiarando' le tue variabili - ti dico che il byte 1 è x
, il byte 2 è y
e mentre scrivi ogni riga di codice, caricando e memorizzando i registri, tu (come essere umano) devi ricordare quale è x
e quale uno è y
, perché il sistema non ha idea. E tu (come essere umano) devi ricordare di che tipo x
e y
sei, perché di nuovo - il sistema non ha idea.