Что делает кастинг на уровне компилятора / машины? - PullRequest
8 голосов
/ 24 марта 2009

Я часто задавался вопросом, что именно делает кастинг на уровне компилятора или машины. Что это делает с 0 и 1 в памяти?

Может кто-нибудь указать мне на хорошую литературу.

Ответы [ 7 ]

6 голосов
/ 24 марта 2009

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

Если приведение невозможно во время компиляции из-за несовместимых типов, выдается ошибка. Если приведение невозможно во время выполнения, генерируется исключение.

Вики-страница о преобразовании типов содержит дополнительную информацию.

2 голосов
/ 24 марта 2009

Что касается Casting, полезной литературой будет Спецификация виртуальной машины JavaTM .

В разделе Конверсии и рекламные акции вы увидите, что существует шесть широких типов конверсий:

  • Преобразование идентичности
  • Расширение примитивных преобразований
  • Сужение примитивных преобразований
  • Расширение эталонных преобразований
  • Сужение эталонных преобразований
  • Строковые преобразования

Существует пять контекстов преобразования, в которых могут встречаться выражения преобразования, включая Преобразование приведения :

Контексты литья позволяют использовать:

  • преобразование личности,
  • расширяющееся примитивное преобразование,
  • сужение примитивного преобразования,
  • расширение конверсии или
  • сужение эталонного преобразования.

Таким образом, преобразования приведения являются более инклюзивными, чем преобразования с использованием присваивания или вызова метода: приведение может выполнять любое разрешенное преобразование, кроме преобразования строк.

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

Некоторые приведенные типы могут быть неверными во время компиляции и привести к ошибке во время компиляции. В противном случае, либо приведение может быть подтверждено во время компиляции, либо требуется проверка достоверности во время выполнения. (Подробнее см. JavaTM Language Specification .)
Если значение во время выполнения является нулевой ссылкой, тогда приведение разрешено. Если проверка во время выполнения не удалась, выдается исключение ClassCastException.

2 голосов
/ 24 марта 2009

В C для нечисловых типов приведение к нулю и нулям в памяти ничего не дает.

Для числовых типов компилятор C выполняет преобразование таким образом, чтобы числовое значение оставалось таким же, насколько это возможно.

Если вы хотите привести числовые типы без изменения битовых значений, вам нужно использовать объединение или указатели преобразования (последний код иллюстрирует последнее):

float a;
int b = 3;

a = *((float*)&b);
1 голос
/ 24 марта 2009

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

Компилятор поддерживает список (называемый таблицей символов ) переменных имен , используемых в любой конкретной точке программы, и некоторую информацию о переменных. Список информации включает в себя:

  • их назначенное хранилище (в этом регистре, в той ячейке памяти и т. Д.) *
  • какого они типа (то есть целое число или строка или SubWhatsitObj), включая любое ограничение (например, постоянство)
  • любая информация о связи, необходимая компилятору

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

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

1 голос
/ 24 марта 2009

Нужно также понимать, как ссылки работают как во время компиляции, так и во время выполнения.

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

Так что, если ваша ссылка Object, вызов toString () делает правильные вещи и находит наиболее производный метод toString (). Приведение необходимо для того, чтобы среда выполнения могла гарантировать, что у любой данной ссылки действительно есть целевые методы для каждого метода, представленного в ссылке. После передачи приведения из X в Y любая ссылка типа Y может быть уверена, что все ее методы доступны по приведенной ссылке (sp).

1 голос
/ 24 марта 2009

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

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

Я пытался погуглить некоторые сведения о правилах для числового приведения, но вокруг не так много. Вы можете попробовать стандарт C99 , но я не уверен, что он вас ошеломит. IIRC, правила:

  • Приведение вниз (большой тип -> меньший тип, например double -> float -> int -> byte) обрезает информацию, которая не может быть представлена ​​(поэтому double-> float потеряет точность, -> int потеряет все десятичные разряды + округление не будет).

  • Приведение (меньший тип -> больший тип) означает заполнение дополнительных битов нулем.

Конечно, есть числа, которые вы не можете реально представить (например, 0,1). Любая операция над ними даже без приведения потеряет информацию (поэтому 0,1 * 10 может быть! = 1,0).

1 голос
/ 24 марта 2009

Предполагая, что это просто приведение ссылочного типа, а не преобразование (например, int в байты), я считаю, что это делает следующее:

1) Проверьте, является ли ссылка нулевой - если так, выйдите. 2) Следуйте по ссылке, чтобы найти объект в памяти. В заголовке объекта есть информация о типе. 3) Из информации о типе проверьте, находится ли целевой тип в иерархии. Если это не так, бросьте ClassCastException с соответствующей информацией.

«Биты» результата всегда совпадают с «битами» входа (при условии, что является выходом, а не исключением), но тогда JVM знает тип ссылки поэтому другие операции гарантированно будут успешными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...