Как компьютер отличает «\ 0» (нулевой символ) от «unsigned int = 0»?

29

Если в данной ситуации у вас есть массив символов (заканчивающийся, конечно, нулевым символом), и сразу после этого, в следующей позиции в памяти, вы хотите сохранить 0как целое число без знака, как компьютер различает эти два?

Angelixus
источник
18
Вы спрашиваете о типичных компьютерах, ответы на которые совершенно верны. Однако раньше были некоторые архитектуры, которые используют помеченную память для различения типов данных.
Гравитация
12
Таким же образом компьютер не может отличить 4-байтовое число с плавающей точкой от 4-байтового целого числа (представляющего совершенно другое число).
Хаген фон Айцен
6
Хотя конец строки 0x00 является обычным явлением, существуют языки, в которых используются строки с префиксом длины. Первый или два байта будут содержать количество байтов в строке. Таким образом, 0x00 в конце не требуется. Кажется, я помню, как Паскаль и Бейсик делали это. Возможно, и COBOL.
горит
@lit также форматы заголовков во многих протоколах связи. «Привет, я такой тип сообщения, и у меня много байтов». Часто из-за необходимости хранить сложные типы данных внутри, нулевое завершение становится намного более сложным для анализа.
mathreadler
1
@lit: Большинство вариантов Pascal и BASIC да, а также PL / I и Ada - и в Java, поскольку совместное использование подстрок было отброшено в 7u6, эффективно использует префикс длины массива - но только в COBOL: вы можете читать данные из pic X occurs m to n depending on v( и счет может быть где угодно, а не только непосредственно), но хранить его сложнее.
dave_thompson_085

Ответы:

86

Это не так.

Терминатор строки - это байт, содержащий все 0 битов.

Целое число без знака - это два или четыре байта (в зависимости от вашей среды), каждый из которых содержит все 0 битов.

Два элемента хранятся по разным адресам. Ваш скомпилированный код выполняет операции, подходящие для строк в первом местоположении, и операции, подходящие для двоичных чисел без знака в последнем. (Если у вас нет ошибки в вашем коде или опасно умного кода!)

Но все эти байты выглядят одинаково для процессора. Данные в памяти (в большинстве распространенных в настоящее время архитектур наборов команд) не имеют какого-либо связанного с ними типа. Это абстракция, которая существует только в исходном коде и что-то значит только для компилятора.

Редактирование добавлено: В качестве примера: вполне возможно, даже обычное, выполнить арифметику для байтов, составляющих строку. Если у вас есть строка из 8-битных символов ASCII, вы можете преобразовать буквы в строке между прописными и строчными буквами, добавив или вычтя 32 (десятичное). Или, если вы переводите в другой символьный код, вы можете использовать их значения в качестве индексов в массиве, элементы которого обеспечивают эквивалентное битовое кодирование в другом коде.

Для процессора символы - это действительно очень короткие целые числа. (восемь бит каждый вместо 16, 32 или 64). Для нас, людей, их значения связаны с читаемыми символами, но процессор не имеет об этом никакого представления. Он также ничего не знает о соглашении «C», заключающемся в том, что «нулевой байт заканчивает строку» (и, как многие отмечали в других ответах и ​​комментариях, существуют среды программирования, в которых это соглашение вообще не используется). ,

Конечно, в x86 / x64 есть некоторые инструкции, которые часто используются со строками - например, с префиксом REP - но вы также можете использовать их в массиве целых чисел, если они достигают желаемого результата.

Джейми Ханрахан
источник
14
Вот почему разработчики должны быть осторожны со строками. Если у вас есть, скажем, 100 последовательных байтов, вы можете разместить в нем не более 99 1-байтовых символов плюс терминатор в последнем байте. Если вы напишете туда 100-байтовую строку, программа не сможет выяснить, что строка заканчивается, и продолжит чтение последовательных байтов до совпадения нулевого байта. Если длина строки превышает 100 байтов, она перезапишет некоторые смежные данные. Языки программирования высокого уровня (Java, C #, JS и т. Д.) Сами позаботятся об этом, но в низкоуровневых языках, таких как C, C ++, сборка - это ответственность dev.
Гроностай
18
@gronostaj Ваш комментарий немного сбивает с толку: в отличие от C, строки C ++ также позаботятся об этом автоматически. C ++ также обычно не классифицируется как язык низкого уровня (и даже C иногда нет).
Конрад Рудольф
5
Существуют (старые) архитектуры ЦП, которые имеют маркеры типов в значениях данных, поэтому разыменование целого числа в качестве указателя приведет к исключению.
Саймон Рихтер
8
@JamieHanrahan Процессор IA64 имеет бит под названием NaT (или «Не вещь»), который может выдавать исключение, если для него установлено значение.
ErikF
4
@KonradRudolph «автоматический» не означает «надежный», конечно, не в C ++
rackandboneman
5

Короче говоря, нет никакой разницы (за исключением того, что int имеет ширину 2 или 4 байта, а char только 1).

Дело в том, что все современные библиотеки либо используют технику нулевого терминатора, либо хранят длину строки. И в обоих случаях программа / компьютер знает, что она достигла конца строки, когда она либо прочитала нулевой символ, либо прочитала столько символов, сколько ему говорит размер.

Проблемы с этим запуском, когда нулевой терминатор отсутствует или длина указана неверно, так как тогда программа начинает читать из памяти, которая не должна.

BrainStone
источник
3
Ох, есть разница в коротких - на самом деле, короткие - это вид, который очень печально зависит от типа данных, зависящих от машины :)
rackandboneman
2

Нет никакой разницы. Машинный код (ассемблер) не имеет переменных типов, вместо этого тип данных определяется инструкцией.

Лучшим примером будет, intи float, если у вас есть 4 байта в памяти, нет никакой информации о том, является ли это intили или float(или что-то еще полностью), однако есть 2 различные инструкции для целочисленного добавления и добавления с плавающей запятой, так что если целочисленное добавление инструкция используется для данных, затем это целое число, и наоборот.

То же самое со строками, если у вас есть код, который, скажем, просматривает адрес и считает байты до тех пор, пока он не достигнет \0байта, вы можете думать о нем как о функции, вычисляющей длину строки.

Конечно, программирование, подобное этому, было бы полным безумием, поэтому у нас есть языки более высокого уровня, которые компилируются в машинный код, и почти нет программ непосредственно на ассемблере.

kajacx
источник
2

Научный ответ одним словом будет: метаданные.

Метаданные сообщают компьютеру, являются ли некоторые данные в определенном месте int, строкой, программным кодом или чем-то еще. Эти метаданные могут быть частью программного кода (как упоминал Джейми Ханрахан) или могут быть явно где-то сохранены.

Современные процессоры часто могут различать области памяти, назначенные программному коду и областям данных (например, бит NX https://en.wikipedia.org/wiki/NX_bit ). Некоторые экзотические устройства также могут различать строки и числа, да. Но обычный случай заключается в том, что Программное обеспечение решает эту проблему, будь то неявные метаданные (в коде) или явные метаданные (объектно-ориентированные виртуальные машины часто хранят метаданные (информацию о типе / классе) как часть данных (объекта)). ,

Преимущество неразличения разных видов данных заключается в том, что некоторые операции становятся очень простыми. Подсистеме ввода / вывода не обязательно нужно знать, являются ли данные, которые она только читает или записывает на диск, на самом деле программный код, читаемый человеком текст или числа. Это всего лишь биты, которые транспортируются через машину. Позвольте программному коду разобраться с необычными проблемами при наборе текста.

Klaws
источник
0

Это не так. Ты сделай это!

Или ваш компилятор / интерпретатор.

Если инструкция скажет компьютеру добавить 0число, оно сделает это. Если они скажут компьютеру прекратить печатать данные после того 0, как они \0'получат, как символ, он это сделает.

Языки имеют механизмы, обеспечивающие обработку данных. В C переменных имеют тип, такие как int, floatи char, и компилятор генерирует правильные инструкции для каждого типа данных. Но C позволяет преобразовывать данные из переменной в другую переменную другого типа, даже указатель на которую можно использовать в качестве числа. Для компьютера это все биты, как и любой другой.

Карлос Прадо
источник
0

Нулевой символ - один байт, а беззнаковое целое - два байта.

Квентин 2
источник