Como um computador diferencia '\ 0' (caractere nulo) de "unsigned int = 0"?

29

Se em uma determinada situação, você tiver uma matriz de caracteres (terminando, é claro, com o caractere nulo) e logo depois, na próxima posição imediata na memória, desejar armazenar 0como um int não assinado, como o computador diferencia esses dois?

Angelixus
fonte
18
Você está perguntando sobre computadores típicos sobre quais respostas estão completamente corretas. No entanto, costumava haver algumas arquiteturas que usam memória marcada para distinguir entre tipos de dados.
grawity
12
Da mesma maneira que o computador não pode diferenciar um número flutuante de 4 bytes de um número inteiro de 4 bytes (reperes- sionando um número muito diferente).
Hagen von Eitzen
6
Embora seja comum finalizar uma string com 0x00, existem idiomas que usam cadeias com prefixo de comprimento. O primeiro byte ou dois conteria o número de bytes na string. Dessa forma, um 0x00 no final não é necessário. Eu me lembro de Pascal e BASIC fazendo isso. Talvez COBOL também.
aceso
O @lit também formata os cabeçalhos em muitos protocolos de comunicação. "Olá, sou esse tipo de mensagem e tenho muitos bytes". Muitas vezes, como você precisa armazenar tipos de dados complexos, a terminação nula se torna muito mais problemática de analisar.
mathreadler
1
@lit: A maioria das variantes de Pascal e BASIC sim, e PL / I e Ada - e em Java desde que o compartilhamento de substring foi eliminado no 7u6 efetivamente usa o prefixo de comprimento da matriz - mas COBOL é apenas uma espécie de: você pode ler dados de pic X occurs m to n depending on v( e a contagem pode estar em qualquer lugar, não apenas imediatamente antes), mas armazená- la é mais complicada.
dave_thompson_085

Respostas:

86

Não faz.

O terminador de string é um byte que contém todos os 0 bits.

O int não assinado é de dois ou quatro bytes (dependendo do seu ambiente), cada um contendo todos os 0 bits.

Os dois itens são armazenados em endereços diferentes. Seu código compilado executa operações adequadas para seqüências de caracteres no local anterior e operações adequadas para números binários não assinados no último. (A menos que você tenha um bug no seu código ou algum código perigosamente inteligente!)

Mas todos esses bytes parecem iguais à CPU. Os dados na memória (na maioria das arquiteturas de conjuntos de instruções comuns atualmente) não têm nenhum tipo associado a eles. Essa é uma abstração que existe apenas no código-fonte e significa algo apenas para o compilador.

Edição adicionada: como exemplo: é perfeitamente possível, até comum, executar aritmética nos bytes que compõem uma sequência. Se você tiver uma sequência de caracteres ASCII de 8 bits, poderá converter as letras entre maiúsculas e minúsculas adicionando ou subtraindo 32 (decimal). Ou, se você estiver traduzindo para outro código de caractere, poderá usar seus valores como índices em uma matriz cujos elementos fornecem a codificação de bits equivalente no outro código.

Para a CPU, os caracteres são realmente inteiros extra-curtos. (oito bits cada, em vez de 16, 32 ou 64.) Para nós, humanos, seus valores estão associados a caracteres legíveis, mas a CPU não faz ideia disso. Também não sabe nada sobre a convenção "C" de "byte nulo termina uma string" (e, como muitos observaram em outras respostas e comentários, há ambientes de programação nos quais essa convenção não é usada) .

Para ter certeza, existem algumas instruções no x86 / x64 que tendem a ser muito usadas com cadeias de caracteres - o prefixo REP, por exemplo - mas você pode usá-las também em uma matriz de números inteiros, se atingirem o resultado desejado.

Jamie Hanrahan
fonte
14
É por isso que os desenvolvedores precisam ter cuidado com as strings. Se você tiver, digamos, 100 bytes consecutivos, poderá caber no máximo 99 caracteres de 1 byte, além do terminador no último byte. Se você escrever uma string de 100 bytes, o programa não poderá descobrir que a string termina aí e continuará lendo bytes consecutivos até um byte zero coincidente. Se a cadeia tiver mais de 100 bytes, ela substituirá alguns dados adjacentes. Linguagens de programação de alto nível (Java, C #, JS etc.) cuidam disso sozinhas, mas em idiomas de baixo nível, como C, C ++, assembly, é responsabilidade do desenvolvedor.
Gronostaj # 1/18
18
@gronostaj Seu comentário é um pouco confuso: Ao contrário do C, as strings C ++ também cuidam disso automaticamente. O C ++ também não é geralmente classificado como uma linguagem de baixo nível (e até o C às vezes não é).
9289 Konrad Rudolph #
5
Existem arquiteturas de CPU (antigas) que possuem marcadores de tipo nos valores dos dados, portanto, a exclusão de um número inteiro como ponteiro dará uma exceção.
Simon Richter
8
@JamieHanrahan O processador IA64 tem um pouco chamado NaT (ou "Not a Thing") que pode gerar uma exceção se um valor tiver sido definido.
ErikF
4
@KonradRudolph "automático" não significa "infalível", certamente não em C ++
rackandboneman
5

Em resumo, não há diferença (exceto que um int tem 2 ou 4 bytes de largura e um char apenas 1).

O fato é que todas as bibliotecas modernas usam a técnica terminator nula ou armazenam o comprimento de uma string. E em ambos os casos, o programa / computador sabe que chegou ao final de uma string quando lê um caractere nulo ou lê quantos caracteres o tamanho indica.

Problemas com esse início quando o terminador nulo está ausente ou o comprimento está errado, pois o programa começa a ler da memória que não deveria.

BrainStone
fonte
3
Oh, há uma diferença em suma - na verdade, curto é tipo de notório por ser um tipo de dados depende muito da máquina :)
rackandboneman
2

Não há diferença. O código da máquina (montador) não possui tipos de variáveis, mas o tipo dos dados é determinado pela instrução.

Um exemplo melhor seria inte float, se você tiver 4 bytes na memória, não há informações sobre se é um intou um float(ou algo completamente diferente); no entanto, existem 2 instruções diferentes para adição de número inteiro e adição de número flutuante, portanto, se a adição de número inteiro A instrução é usada nos dados, então é um número inteiro e vice-versa.

O mesmo com as strings, se você possui um código que, digamos, olha para um endereço e conta bytes até atingir um \0byte, você pode pensar nele como uma função que calcula o comprimento da string.

É claro que programar como esse seria uma loucura completa, por isso temos linguagens de nível superior que compilam com código de máquina e quase nenhum programa diretamente no assembler.

Dogukan - Malt.fr - WordPress
fonte
2

A resposta científica de uma única palavra seria: metadados.

Os metadados informam ao computador se alguns dados em um determinado local são int, uma string, código de programa ou o que for. Esses metadados podem fazer parte do código do programa (como Jamie Hanrahan mencionou) ou podem ser armazenados explicitamente em algum lugar.

As CPUs modernas costumam distinguir entre regiões de memória atribuídas ao código do programa e regiões de dados (por exemplo, o NX Bit https://en.wikipedia.org/wiki/NX_bit ). Algum hardware exótico também pode distinguir entre cadeias e números, sim. Mas o caso usual é que o Software cuida desse problema, apesar de metadados implícitos (no código) ou explícitos (as VMs orientadas a objetos geralmente armazenam os metadados (informações de tipo / classe) como parte dos dados (objeto)) .

Uma vantagem de não distinguir entre diferentes tipos de dados é que algumas operações se tornam muito simples. O subsistema de E / S não precisa necessariamente saber se os dados dos quais apenas lê ou grava no disco são realmente código de programa, texto ou números legíveis por humanos. São apenas bits que são transportados pela máquina. Deixe o código do programa lidar com os problemas de digitação sofisticados.

Klaws
fonte
0

Não faz. Faz você!

Ou seu compilador / intérprete.

Se as instruções solicitarem ao computador para adicionar o 0número, isso será possível. Se eles disserem ao computador para parar para imprimir dados depois de chegar ao 0, como um ' \0'char ' , ele fará isso.

Os idiomas têm mecanismos para garantir como tratar os dados. Em C, as variáveis ​​têm tipos, como int, floate char, e o compilador gera instruções corretas para cada tipo de dados. Mas C permite converter dados de uma variável para outra variável de tipo diferente, até um ponteiro pode ser usado como um número. Para o computador, é tudo como qualquer outro.

Carlos Prado
fonte
0

Um caractere nulo é um byte e um int não assinado é dois bytes.

Quentin 2
fonte