¿Cómo diferencia una computadora '\ 0' (carácter nulo) de “unsigned int = 0”?

29

Si en una situación dada, tiene una serie de caracteres (que termina, por supuesto, con el carácter nulo) y justo después de eso, en la siguiente posición inmediata en la memoria, desea almacenar 0como un int sin signo, ¿cómo diferencia la computadora entre estos ¿dos?

Angelixus
fuente
18
Estás preguntando sobre computadoras típicas sobre las cuales las respuestas son completamente correctas. Sin embargo, solía haber algunas arquitecturas que usan memoria etiquetada para distinguir entre los tipos de datos.
Grawity
12
De la misma manera, la computadora no puede diferenciar un flotante de 4 bytes de un entero de 4 bytes (representando un número muy diferente).
Hagen von Eitzen
66
Si bien terminar una cadena con 0x00 es común, hay idiomas que usan cadenas con prefijo de longitud. El primer byte o dos contendría el número de bytes en la cadena. De esta manera, no se necesita un 0x00 al final. Me parece recordar que Pascal y BASIC hicieron eso. Quizás COBOL también.
encendido
@lit también formatea encabezados en muchos protocolos de comunicación. "Hola, soy este tipo de mensaje y tengo tantos bytes". A menudo, debido a que necesita almacenar tipos de datos complejos en su interior, la terminación nula se vuelve mucho más problemática de analizar.
mathreadler
1
@lit: La mayoría de las variantes de Pascal y BASIC sí, y PL / I y Ada, y en Java, ya que el uso compartido de la subcadena se eliminó en 7u6, usa efectivamente el prefijo de longitud de la matriz, pero COBOL solo como: puede leer datos de pic X occurs m to n depending on v( y el conteo puede estar en cualquier lugar, no solo inmediatamente antes), pero almacenarlo es más complicado.
dave_thompson_085

Respuestas:

86

No lo hace.

El terminador de cadena es un byte que contiene todos los 0 bits.

El int sin signo tiene dos o cuatro bytes (dependiendo de su entorno), cada uno de los cuales contiene todos los 0 bits.

Los dos elementos se almacenan en diferentes direcciones. Su código compilado realiza operaciones adecuadas para cadenas en la ubicación anterior y operaciones adecuadas para números binarios sin signo en la última. (¡A menos que tenga un error en su código o algún código peligrosamente inteligente!)

Pero todos estos bytes tienen el mismo aspecto para la CPU. Los datos en memoria (en la mayoría de las arquitecturas de conjuntos de instrucciones comunes actualmente) no tienen ningún tipo asociado. Esa es una abstracción que existe solo en el código fuente y significa algo solo para el compilador.

Edición agregada: como ejemplo: es perfectamente posible, incluso común, realizar operaciones aritméticas en los bytes que forman una cadena. Si tiene una cadena de caracteres ASCII de 8 bits, puede convertir las letras en la cadena entre mayúsculas y minúsculas sumando o restando 32 (decimal). O si está traduciendo a otro código de caracteres, puede usar sus valores como índices en una matriz cuyos elementos proporcionan la codificación de bits equivalente en el otro código.

Para la CPU, los caracteres son realmente enteros extra cortos. (ocho bits cada uno en lugar de 16, 32 o 64). Para nosotros, los humanos, sus valores están asociados con caracteres legibles, pero la CPU no tiene idea de eso. Tampoco sabe nada acerca de la convención "C" de "byte nulo termina una cadena" (y, como muchos han señalado en otras respuestas y comentarios, hay entornos de programación en los que esa convención no se utiliza en absoluto) .

Para estar seguros, hay algunas instrucciones en x86 / x64 que tienden a usarse mucho con cadenas, el prefijo REP, por ejemplo, pero también puede usarlas en una matriz de enteros, si logran el resultado deseado.

Jamie Hanrahan
fuente
14
Es por eso que los desarrolladores deben tener cuidado con las cadenas. Si tiene, digamos, 100 bytes consecutivos, puede incluir como máximo 99 caracteres de 1 byte más el terminador en el último byte. Si escribe una cadena de 100 bytes, el programa no podrá darse cuenta de que la cadena termina allí y continuará leyendo bytes consecutivos hasta un byte cero coincidente. Si la cadena tiene más de 100 bytes de longitud, sobrescribirá algunos datos adyacentes. Los lenguajes de programación de alto nivel (Java, C #, JS, etc.) se encargan de esto ellos mismos, pero en idiomas de bajo nivel como C, C ++, el ensamblaje es la responsabilidad del desarrollador.
gronostaj
18
@gronostaj Su comentario es un poco confuso: a diferencia de C, las cadenas de C ++ también se encargan de esto automáticamente. C ++ tampoco se clasifica generalmente como un lenguaje de bajo nivel (e incluso C a veces no)
Konrad Rudolph el
55
Hay arquitecturas de CPU (antiguas) que tienen marcadores de tipo en los valores de los datos, por lo que desreferenciar un entero como puntero dará una excepción.
Simon Richter
8
@JamieHanrahan El procesador IA64 tiene un bit llamado NaT (o "Not a Thing") que puede generar una excepción si un valor lo tiene establecido.
ErikF
44
@KonradRudolph "automático" no significa "infalible", ciertamente no en C ++
rackandboneman
5

En resumen, no hay diferencia (excepto que un int tiene 2 o 4 bytes de ancho y un char solo 1).

La cuestión es que todas las bibliotecas modernas usan la técnica de terminación nula o almacenan la longitud de una cadena. Y en ambos casos, el programa / computadora sabe que alcanzó el final de una cadena cuando lee un carácter nulo o ha leído tantos caracteres como el tamaño le indica.

Los problemas con este inicio comienzan cuando falta el terminador nulo o la longitud es incorrecta, ya que el programa comienza a leer de la memoria que no debería.

BrainStone
fuente
3
Oh, hay una diferencia en fin - de hecho, es una especie de corta conocidos por ser una máquina de tipo de datos depende :)
rackandboneman
2

No hay diferencia. El código de máquina (ensamblador) no tiene tipos variables, sino que el tipo de datos está determinado por la instrucción.

Un mejor ejemplo sería inty float, si tiene 4 bytes en la memoria, no hay información de si es una into una float(o algo completamente diferente), sin embargo, hay 2 instrucciones diferentes para la suma de enteros y la suma flotante, por lo que si la suma de enteros la instrucción se usa en los datos, luego es un número entero y viceversa.

Lo mismo con las cadenas, si tiene un código que, por ejemplo, mira una dirección y cuenta los bytes hasta que alcanza un \0byte, puede considerarla como una función que calcula la longitud de la cadena.

Por supuesto, una programación como esta sería una locura total, por eso tenemos lenguajes de nivel superior que compilan en código máquina y casi ningún programa en ensamblador directamente.

kajacx
fuente
2

La respuesta científica de una sola palabra sería: metadatos.

Los metadatos le dicen a la computadora si algunos datos en una ubicación determinada son int, una cadena, un código de programa o lo que sea. Estos metadatos pueden formar parte del Código del programa (como mencionó Jamie Hanrahan) o pueden almacenarse explícitamente en algún lugar.

Las CPU modernas a menudo pueden distinguir entre regiones de memoria asignadas a código de programa y regiones de datos (por ejemplo, el NX Bit https://en.wikipedia.org/wiki/NX_bit ). Algunos hardware exóticos también pueden distinguir entre cadenas y números, sí. Pero el caso habitual es que el Software se ocupa de este problema, ya sea a través de metadatos implícitos (en el código) o metadatos explícitos (las máquinas virtuales orientadas a objetos a menudo almacenan los metadatos (información de tipo / clase) como parte de los datos (objeto)) .

Una ventaja de no distinguir entre diferentes tipos de datos es que algunas operaciones se vuelven muy simples. El subsistema de E / S no necesariamente necesita saber si los datos que solo lee o escribe en el disco son en realidad códigos de programas, textos o números legibles por humanos. Todo son solo bits que se transportan a través de la máquina. Deje que el código del programa se ocupe de los problemas de escritura sofisticados.

Klaws
fuente
0

No lo hace. ¡Hazlo tu!

O tu compilador / intérprete.

Si las instrucciones le dicen a la computadora que agregue el 0número, lo hará. Si le dicen a la computadora que se detenga para imprimir datos después de llegar al 0, como ' \0'char ' , lo hará.

Los idiomas tienen mecanismos para garantizar cómo tratar los datos. En C las variables tienen tipos, como int, floaty char, y el compilador genera instrucciones correctas para cada tipo de datos. Pero C le permite convertir datos de una variable a otra variable de diferente tipo, incluso un puntero puede usarse como un número. Para la computadora todo son bits como cualquier otro.

carlos prado
fuente
0

Un carácter nulo es un byte y un int sin signo es dos bytes.

Quentin 2
fuente