In che modo un computer differenzia '\ 0' (carattere null) da “unsigned int = 0”?


29

Se in una determinata situazione, hai una matrice di caratteri (che termina ovviamente con il carattere null) e subito dopo, nella posizione immediatamente successiva in memoria, vuoi archiviare 0come int senza segno, in che modo il computer distingue tra questi Due?


18
Stai chiedendo dei computer tipici su cui le risposte sono completamente giuste. Tuttavia, esistevano alcune architetture che utilizzano la memoria con tag per distinguere i tipi di dati.
Grawity

12
Allo stesso modo il computer non può differenziare un float da 4 byte da un numero intero da 4 byte (che rappresenta un numero molto diverso).
Hagen von Eitzen,

6
Mentre è comune terminare una stringa con 0x00, ci sono lingue che usano stringhe con prefisso di lunghezza. Il primo o due byte conterrebbero il numero di byte nella stringa. In questo modo, non è necessario uno 0x00 alla fine. Mi sembra di ricordare che Pascal e BASIC lo abbiano fatto. Forse anche COBOL.
acceso il

@lit ha anche formati di intestazione in molti protocolli di comunicazione. "Ciao, sono questo tipo di messaggio e sono lungo così tanti byte". Spesso perché è necessario archiviare tipi di dati complessi all'interno, la terminazione nulla diventa molto più problematica da analizzare.
Mathathler,

1
@lit: la maggior parte delle varianti di Pascal e BASIC sì, e PL / I e Ada - e in Java da quando la condivisione della sottostringa è stata interrotta in 7u6 utilizza effettivamente il prefisso della lunghezza dell'array - ma COBOL solo una sorta di: puoi leggere i dati da pic X occurs m to n depending on v( e il conteggio può essere ovunque, non solo immediatamente prima), ma memorizzarlo è più complicato.
dave_thompson_085,

Risposte:


86

Non

Il terminatore di stringa è un byte contenente tutti gli 0 bit.

L'int senza segno è di due o quattro byte (a seconda del proprio ambiente) ciascuno contenente tutti 0 bit.

I due articoli sono memorizzati a indirizzi diversi. Il codice compilato esegue operazioni adatte a stringhe nella prima posizione e operazioni adatte a numeri binari senza segno su quest'ultima. (A meno che tu non abbia un bug nel tuo codice o un codice pericolosamente intelligente!)

Ma tutti questi byte sembrano uguali per la CPU. I dati in memoria (nella maggior parte delle architetture di set di istruzioni attualmente comuni) non hanno alcun tipo associato ad esso. Questa è un'astrazione che esiste solo nel codice sorgente e significa qualcosa solo per il compilatore.

Modifica aggiunta: Ad esempio: è perfettamente possibile, anche comune, eseguire l'aritmetica sui byte che compongono una stringa. Se si dispone di una stringa di caratteri ASCII a 8 bit, è possibile convertire le lettere nella stringa tra maiuscole e minuscole aggiungendo o sottraendo 32 (decimale). Oppure, se stai traducendo in un altro codice di caratteri, puoi usare i loro valori come indici in un array i cui elementi forniscono la codifica di bit equivalente nell'altro codice.

Per la CPU i caratteri sono numeri interi estremamente brevi. (otto bit ciascuno invece di 16, 32 o 64.) A noi umani i loro valori sono associati a caratteri leggibili, ma la CPU non ne ha idea. Inoltre, non sa nulla della convenzione "C" di "byte null termina una stringa", (e come molti hanno notato in altre risposte e commenti, ci sono ambienti di programmazione in cui quella convenzione non è affatto utilizzata) .

A dire il vero, ci sono alcune istruzioni in x86 / x64 che tendono ad essere usate molto con le stringhe - il prefisso REP, ad esempio - ma puoi anche usarle su una matrice di numeri interi, se raggiungono il risultato desiderato.


14
Ecco perché gli sviluppatori devono fare attenzione con le stringhe. Se hai, diciamo, 100 byte consecutivi, puoi inserire al massimo 99 caratteri da 1 byte più il terminatore nell'ultimo byte. Se scrivi una stringa di 100 byte, il programma non sarà in grado di capire che la stringa finisce lì e continuerà a leggere byte consecutivi fino a un byte zero casuale. Se la stringa è lunga più di 100 byte, sovrascriverà alcuni dati adiacenti. I linguaggi di programmazione di alto livello (Java, C #, JS ecc.) Se ne occupano da soli, ma in lingue di basso livello come C, C ++, assembly è la responsabilità di dev.
gronostaj,

18
@gronostaj Il tuo commento è un po 'confuso: a differenza delle stringhe C, C ++ si occupa anche automaticamente di questo. Anche il C ++ non è generalmente classificato come un linguaggio di basso livello (e talvolta anche il C non lo è).
Konrad Rudolph,

5
Esistono (vecchie) architetture CPU che hanno marcatori di tipo sui valori dei dati, quindi il dereferenziare un numero intero come puntatore darà un'eccezione.
Simon Richter,

8
@JamieHanrahan Il processore IA64 ha un bit chiamato NaT (o "Not a Thing") che può generare un'eccezione se è stato impostato un valore.
ErikF

4
@KonradRudolph "automatico" non significa "infallibile", certamente non in C ++
rackandboneman

5

In breve non c'è differenza (tranne che un int è largo 2 o 4 byte e un carattere solo 1).

Il fatto è che tutte le moderne librerie usano la tecnica null terminator o memorizzano la lunghezza di una stringa. E in entrambi i casi il programma / computer sa che ha raggiunto la fine di una stringa quando legge un carattere nullo o ha letto tanti caratteri quanti ne indica la dimensione.

Problemi con questo inizio quando manca il terminatore null o la lunghezza è errata poiché il programma inizia a leggere dalla memoria che non dovrebbe.


3
Oh, c'è una differenza in breve - in realtà, in breve è un po 'noto per essere un tipo di dati molto dipendente dalla macchina :)
rackandboneman

2

Non c'è differenza. Il codice macchina (assemblatore) non ha tipi variabili, ma il tipo di dati è determinato dall'istruzione.

Un esempio migliore sarebbe inte float, se hai 4 byte in memoria, non ci sono informazioni sul fatto che sia un into un float(o qualcos'altro interamente), tuttavia ci sono 2 diverse istruzioni per l'aggiunta di numeri interi e l'aggiunta float, quindi se l'aggiunta di numeri interi l'istruzione viene utilizzata sui dati, quindi è un numero intero e viceversa.

Lo stesso vale per le stringhe, se si dispone di un codice che, ad esempio, osserva un indirizzo e conta i byte fino a quando non raggiunge un \0byte, è possibile considerarlo come una funzione che calcola la lunghezza della stringa.

Ovviamente programmare in questo modo sarebbe una follia completa, quindi è per questo che abbiamo linguaggi di livello superiore che si compilano in codice macchina e quasi nessuno programma direttamente in assembler.


2

La risposta scientifica a una sola parola sarebbe: metadati.

I metadati indicano al computer se alcuni dati in una determinata posizione sono un int, una stringa, un codice di programma o altro. Questi metadati possono far parte del codice del programma (come menzionato Jamie Hanrahan) o possono essere archiviati in modo esplicito da qualche parte.

Le CPU moderne possono spesso distinguere tra aree di memoria assegnate al codice del programma e aree dati (ad esempio, il bit NX https://en.wikipedia.org/wiki/NX_bit ). Alcuni hardware esotici possono anche distinguere tra stringhe e numeri, sì. Ma il solito caso è che il Software si occupi di questo problema, anche se metadati impliciti (nel codice) o metadati espliciti (le VM orientate agli oggetti spesso archiviano i metadati (informazioni sul tipo / classe) come parte dei dati (oggetto)) .

Un vantaggio di non distinguere tra diversi tipi di dati è che alcune operazioni diventano molto semplici. Il sottosistema I / O non deve necessariamente sapere se i dati che legge o scrive sul disco sono in realtà codice di programma, testo o numeri leggibili dall'uomo. Sono solo pezzi che vengono trasportati attraverso la macchina. Lascia che il codice del programma affronti i problemi di digitazione.


0

Non Lo fai!

O il tuo compilatore / interprete.

Se le istruzioni dicono al computer di aggiungere 0un numero, lo farà. Se dicono al computer di interrompere la stampa dei dati dopo aver raggiunto il carattere 0" \0'char " , lo farà.

Le lingue hanno meccanismi per garantire come trattare i dati. In C le variabili hanno tipi, come int, floate char, e il compilatore genera le giuste istruzioni per ogni tipo di dati. Ma C ti consente di trasmettere i dati da una variabile a un'altra variabile di tipo diverso, anche un puntatore a può essere utilizzato come numero. Per computer è tutto come un altro.


0

Un carattere null è un byte e un int senza segno è due byte.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.