В информатике , типа преобразовании , [1] [2] типа литья , [1] [3] типа принуждения , [3] и типа жонглирование [4] [5] различные пути изменения в экспрессии от одного типа данных к другому . Примером может служить преобразование целочисленного значения в значение с плавающей запятой или его текстовое представление в виде строки и наоборот. Преобразования типов могут использовать преимущества определенных функций иерархий типов или представлений данных.. Два важных аспекта преобразования типа являются происходит ли это неявно (автоматически) или в явном виде , [1] [6] , и является ли базовое представление данных преобразуются из одного представления в другое, или данное представление является лишь переосмыслено как представление другого тип данных. [6] [7] Как правило, можно преобразовывать как примитивные, так и составные типы данных .
У каждого языка программирования есть свои правила преобразования типов. Языки со строгой типизацией обычно выполняют мало неявных преобразований и препятствуют повторной интерпретации представлений, в то время как языки со слабой типизацией выполняют множество неявных преобразований между типами данных. Слабый язык типизации часто позволяет заставить компилятор произвольно интерпретировать элемент данных как имеющий разные представления - это может быть неочевидная ошибка программирования или технический метод для непосредственной работы с базовым оборудованием.
В большинстве языков слово принуждение используется для обозначения неявного преобразования либо во время компиляции, либо во время выполнения . Например, в выражении, сочетающем целые числа и числа с плавающей запятой (например, 5 + 0,1), компилятор автоматически преобразует целочисленное представление в представление с плавающей запятой, чтобы дроби не терялись. Явные преобразования типов указываются либо путем написания дополнительного кода (например, добавления идентификаторов типа или вызова встроенных подпрограмм ), либо путем кодирования подпрограмм преобразования, которые компилятор использует, когда в противном случае он остановился бы из-за несоответствия типов.
В большинстве Algol -подобных языков, таких как Pascal , Modula-2 , Ada и Delphi , преобразования и литья отчетливо различные концепции. В этих языках преобразование относится либо к неявному, либо к явному изменению значения из одного формата хранения данных в другой, например, из 16-битного целого числа в 32-битное целое число. Потребности в хранении могут измениться в результате преобразования, включая возможную потерю точности или усечение. Слово литой , с другой стороны, относится к явным образом изменяя интерпретацию в битовой комбинации , представляющей собой значение от одного типа к другому. Например, 32 смежных бита можно рассматривать как массив из 32 логических значений, 4-байтовую строку, 32-битное целое число без знака или значение с плавающей запятой одинарной точности IEEE. Поскольку хранимые биты никогда не меняются, программист должен знать подробности низкого уровня, такие как формат представления, порядок байтов и потребности выравнивания, чтобы их можно было осмысленно преобразовать.
В C семействе языков и АЛГОЛА 68 , слово литой , как правило , относится к явным преобразованию типа (в отличие от неявного преобразования), в результате чего некоторые двусмысленностей об этом , является ли реинтерпретация битового шаблона или представление реальных данных конверсия. Более важным является множество способов и правил, которые применяются к тому, какой тип данных (или класс) находится с помощью указателя, и как указатель может быть скорректирован компилятором в таких случаях, как наследование объекта (класса).
Сравнение языков
C-подобные языки
Неявное преобразование типа
Неявные преобразования типов, также известные как принуждение , является автоматическим преобразованием типа по компилятору . Некоторые языки программирования позволяют компиляторам обеспечивать принуждение; другие требуют этого.
В выражении смешанного типа данные одного или нескольких подтипов могут быть преобразованы в супертип по мере необходимости во время выполнения, чтобы программа работала правильно. Например, следующий код допустимого языка C :
двойной d ; длинный l ; int i ;если ( d > i ) d = i ; если ( i > l ) l = i ; если ( d == l ) d * = 2 ;
Хотя d , л , и Я принадлежу к разным типам данных, они будут автоматически преобразовываться в одинаковые типы данных каждый раз, когда выполняется сравнение или присваивание. Это поведение следует использовать с осторожностью, посколькумогут возникнуть непредвиденные последствия . Данные могут быть потеряны при преобразовании представлений с плавающей запятой в целое число, поскольку дробные компоненты значений с плавающей запятой будут усечены (округлены в сторону нуля). И наоборот, точность может быть потеряна при преобразовании представлений из целого числа в число с плавающей запятой, поскольку тип с плавающей запятой может быть неспособен точно представить целочисленный тип. Например, этоfloat
может бытьтип одинарной точности IEEE 754 , который не может точно представлять целое число 16777217, в то время как 32-битный целочисленный тип может. Это может привести к неинтуитивному поведению, о чем свидетельствует следующий код:
#include int main ( void ) { int i_value = 16777217 ; float f_value = 16777216.0 ; printf ( "Целое число:% d \ n " , i_value ); printf ( "Число с плавающей запятой:% f \ n " , f_value ); printf ( "Их равенство:% d \ n " , i_value == f_value ); }
В компиляторах, которые реализуют числа с плавающей запятой как одинарную точность IEEE, а целые числа - как минимум 32 бита, этот код даст такую специфическую распечатку:
Целое число: 16777217Число с плавающей запятой: 16777216.000000Их равенство: 1
Обратите внимание, что 1 представляет равенство в последней строке выше. Это странное поведение вызвано неявным преобразованием i_value
в float при сравнении с f_value
. Преобразование приводит к потере точности, что приводит к равенству значений перед сравнением.
Важные выводы:
float
дляint
причин усечения , то есть удаление дробной части.double
доfloat
причин округления цифр.long
toint
вызывает отбрасывание лишних битов более высокого порядка.
Тип продвижение
Одним из особых случаев неявного преобразования типа является повышение типа, когда компилятор автоматически расширяет двоичное представление объектов целочисленных типов или типов с плавающей запятой. Повышения обычно используются с типами, меньшими, чем собственный тип арифметико-логического блока (ALU) целевой платформы , перед арифметическими и логическими операциями, чтобы сделать такие операции возможными, или более эффективными, если ALU может работать с более чем одним типом. C и C ++ выполняют такое продвижение для объектов типа boolean, character, wide character, enumeration и short integer, которые повышаются до int, а также для объектов типа float, которые повышаются до double. В отличие от некоторых других преобразований типов, рекламные акции никогда не теряют точности и не изменяют значение, хранящееся в объекте.
В Java :
int x = 3 ; двойной y = 3,5 ; Система . из . println ( х + у ); // Результат будет 6.5
Явное преобразование типа
Явное преобразование типа - это преобразование типа, которое явно определяется в программе (вместо того, чтобы выполняться компилятором для неявного преобразования типа). Он определяется пользователем в программе.
двойной da = 3,3 ; двойной db = 3,3 ; двойной dc = 3,4 ; int результат = ( int ) da + ( int ) db + ( int ) dc ; // результат == 9 // если бы использовалось неявное преобразование (как с "result = da + db + dc"), результат был бы равен 10
Есть несколько видов явного преобразования.
- проверил
- Перед выполнением преобразования выполняется проверка во время выполнения, чтобы увидеть, может ли целевой тип содержать исходное значение. В противном случае возникает состояние ошибки.
- не отмечен
- Никакой проверки не производится. Если тип назначения не может содержать исходное значение, результат не определен.
- битовая комбинация
- Необработанное битовое представление источника копируется дословно и повторно интерпретируется в соответствии с типом назначения. Этого также можно добиться с помощью псевдонима .
В объектно-ориентированных языках программирования объекты также могут быть понижены : ссылка базового класса приводится к одному из его производных классов.
C # и C ++
В C # преобразование типа может быть выполнено безопасным или небезопасным (т. Е. C-подобным) способом, первый из которых называется приведением типа с проверкой . [8]
Животное животное = новый Кот ();Бульдог b = ( Бульдог ) животное ; // если (животное - Бульдог), stat.type (животное) - Бульдог, иначе исключение b = животное как Бульдог ; // если (животное это Бульдог), b = (Бульдог) животное, иначе b = nullanimal = null ; b = животное как Бульдог ; // b == null
В C ++ аналогичного эффекта можно добиться, используя синтаксис приведения в стиле C ++ .
Животное * животное = новый Кот ;Бульдог * b = static_cast < Бульдог *> ( животное ); // компилируется, только если Animal или Bulldog являются производными от другого (или того же самого) b = dynamic_cast < Bulldog *> ( animal ); // если (животное это Бульдог), b = (Бульдог *) животное, иначе b = nullptrБульдог & br = static_cast < Бульдог &> ( * животное ); // то же, что и выше, но будет сгенерировано исключение, если должен был быть возвращен nullptr // это не видно в коде, где избегается обработка исключений animal = nullptr ; b = dynamic_cast < Бульдог *> ( животное ); // b == nullptrудалить животное ; // всегда свободные ресурсы
Эйфелева
В Eiffel понятие преобразования типов интегрировано в правила системы типов. Правило присвоения гласит, что такое задание, как:
х : = у
допустимо тогда и только тогда, когда тип его исходного выражения y
в этом случае совместим с типом его целевой сущности x
в этом случае. В этом правиле, совместимом с помощью , что тип выражения источника либо соответствует или обращенным к что мишени. Соответствие типов определяется знакомыми правилами полиморфизма в объектно-ориентированном программировании . Например, в приведенном выше назначении тип y
соответствует типу, x
если класс, на котором y
основан, является потомком того, на котором x
основан.
Определение преобразования типов в Eiffel
Действия преобразования типа в Eiffel, в частности преобразование в и преобразование из , определены как:
Тип, основанный на классе CU, преобразуется в тип T на основе класса CT (и T преобразуется из U), если либо
- CT имеет процедуру преобразования, использующую U в качестве типа преобразования, или
- В CU есть список запроса преобразования T в качестве типа преобразования
Пример
Eiffel - это полностью совместимый язык для Microsoft .NET Framework . До разработки .NET у Eiffel уже были обширные библиотеки классов. Использование библиотек типов .NET, особенно с часто используемыми типами, такими как строки, создает проблему преобразования. Существующее программное обеспечение Eiffel использует строковые классы (например, STRING_8
) из библиотек Eiffel, но программное обеспечение Eiffel, написанное для .NET, System.String
во многих случаях должно использовать строковый класс .NET ( ), например, при вызове методов .NET, которые ожидают элементы .NET. тип, передаваемый в качестве аргументов. Таким образом, преобразование этих типов туда и обратно должно быть как можно более плавным.
my_string : STRING_8 - Собственная строка Eiffel my_system_string : SYSTEM_STRING - Собственная строка .NET ... my_string : = my_system_string
В приведенном выше коде объявлены две строки, по одной каждого типа ( SYSTEM_STRING
это совместимый с Eiffel псевдоним для System.String). Поскольку System.String
не соответствует STRING_8
, то указанное выше присвоение допустимо, только если System.String
преобразовано в STRING_8
.
Класс Eiffel STRING_8
имеет процедуру преобразования make_from_cil
для объектов типа System.String
. Процедуры преобразования также всегда обозначаются как процедуры создания (аналогично конструкторам). Ниже приводится отрывок из STRING_8
занятия:
класс STRING_8 ... создать make_from_cil ... преобразовать make_from_cil ({ SYSTEM_STRING }) ...
Наличие процедуры преобразования делает присвоение:
my_string : = my_system_string
семантически эквивалентен:
создать my_string . make_from_cil ( my_system_string )
в котором my_string
создается как новый объект типа STRING_8
с содержимым, эквивалентным содержимому my_system_string
.
Чтобы обработать назначение с перевернутыми исходным источником и целью:
my_system_string : = моя_строка
класс STRING_8
также содержит запрос преобразования, to_cil
который создаст System.String
из экземпляра STRING_8
.
класс STRING_8 ... создать make_from_cil ... преобразовать make_from_cil ({ SYSTEM_STRING }) в_cil : { SYSTEM_STRING } ...
Назначение:
my_system_string : = моя_строка
тогда становится эквивалентным:
my_system_string : = моя_строка . to_cil
В Eiffel настройка преобразования типов включается в код класса, но затем кажется, что это происходит автоматически, как явное преобразование типов в клиентском коде. Включает не только присвоения, но и другие типы вложений, такие как подстановка аргумента (параметра).
Ржавчина
Rust не обеспечивает неявного преобразования (принуждения) типов между примитивными типами. Но явное преобразование типа (приведение) можно выполнить с помощью as
ключевого слова. [9]
println! ( "1000 как u16 равно: {}" , 1000 как u16 );
Проблемы с безопасностью
При взломе приведение типов - это неправильное использование преобразования типа для временного изменения типа данных переменной по сравнению с тем, как он был изначально определен. [10] Это предоставляет возможности для хакеров, поскольку при преобразовании типа после «преобразования типа» переменной в другой тип данных компилятор будет рассматривать эту взломанную переменную как новый тип данных для этой конкретной операции. [11]
Смотрите также
- Понижение
- Информация о типе времени выполнения # динамическое приведение и приведение Java
- Набросок типа
Рекомендации
- ^ a b c Mehrotra, Dheeraj (2008). Компьютерные науки С. Чанда . С. 81–83. ISBN 978-8121929844.
- ^ Языки программирования - дизайн и конструкции . 2013. с. 35. ISBN 978-9381159415.
- ^ а б Рейли, Эдвин (2004). Краткая энциклопедия компьютерных наук . С. 82, 110 . ISBN 0470090952.
- ^ Фентон, Стив (2017). Pro TypeScript: разработка на JavaScript в масштабе приложения . стр. xxiii. ISBN 978-1484232491.
- ^ "PHP: Типаж - Руководство" . php.net . Проверено 27 января 2019 .
- ^ а б Олссон, Микаэль (2013). Краткий справочник по синтаксису C ++ . С. 87–89. ISBN 978-1430262770.
- ^ Крузе, Рудольф; Боргельт, Кристиан; Браун, Кристиан; Мостагим, Саназ; Штейнбрехер, Маттиас (16 сентября 2016 г.). Вычислительный интеллект: методологическое введение . п. 269. ISBN. 978-1447172963.
- ^ Mössenböck, Hanspeter (25 марта 2002 г.). «Advanced C #: Checked Type Casts» (PDF) . Institut für Systemsoftware, Университет Йоханнеса Кеплера в Линце, Fachbereich Informatik. п. 5 . Проверено 4 августа 2011 года .в Учебнике C #
- ^ «Литье - пример ржавчины» . doc.rust-lang.org .
- ^ Jon Erickson Hacking, 2nd Edition: The Art of Exploitation 2008 1593271441 p51 «Приведение типов - это просто способ временно изменить тип данных переменной, несмотря на то, как он был первоначально определен. сказано обрабатывать эту переменную, как если бы это был новый тип данных, но только для этой операции. Синтаксис для приведения типов следующий: (typecast_data_type) variable ... "
- ^ Арпита Гопал,увеличивающий C 2009 8120338618 p.59 "Из вышесказанного ясно, что использование преобразования типов состоит в том, чтобы сделать переменную одного типа, действуя как переменная другого типа для одной единственной операции. Таким образом, используя эту способность преобразования типов, возможно создание символов ASCII путем приведения целого числа к его ... "
Внешние ссылки
- Кастинг в Аде
- Приведение в C ++
- Справочное руководство по C ++ Почему я ненавижу операторы приведения в C ++, Дэнни Калев
- Кастинг на Java
- Неявные преобразования в C #
- Неявное приведение типов на Cppreference.com
- Статические и переинтерпретированные приведения в C ++
- Повышающее и понижающее приведение в F #