29

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

6 ответов6

86

Это не так.

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

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

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

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

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

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

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

5

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

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

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

2

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

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

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

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

2

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

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

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

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

0

Это не так. Ты делаешь это!

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

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

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

0

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .