Преобразование типов


Из Википедии, свободной энциклопедии
  (Перенаправлено из состава Конста )
Перейти к навигации Перейти к поиску

В информатике преобразование типов , [ 1] [2] приведение типов , [1] [3] приведение типов , [3] и жонглирование типами [4] [5] — это разные способы изменения выражения из одного типа данных в другой . . Примером может служить преобразование целочисленного значения в значение с плавающей запятой или его текстовое представление в виде строки и наоборот. Преобразования типов могут использовать определенные функции иерархий типов или представлений данных .. Два важных аспекта преобразования типа: происходит ли оно неявно (автоматически) или явно , [1] [6] и преобразуется ли базовое представление данных из одного представления в другое, или данное представление просто переинтерпретируется как представление другого. тип данных. [6] [7] Как правило, можно преобразовывать как примитивные , так и составные типы данных .

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

В большинстве языков слово принуждение используется для обозначения неявного преобразования либо во время компиляции, либо во время выполнения . Например, в выражении, смешивающем целые числа и числа с плавающей запятой (например, 5 + 0,1), компилятор автоматически преобразует целочисленное представление в представление с плавающей запятой, поэтому дроби не теряются. Явные преобразования типов обозначаются либо написанием дополнительного кода (например, добавлением идентификаторов типов или вызовом встроенных подпрограмм ), либо кодированием подпрограмм преобразования для использования компилятором, когда в противном случае он остановился бы из-за несоответствия типов.

В большинстве ALGOL - подобных языков, таких как Pascal , Modula-2 , Ada и Delphi , преобразование и приведение — совершенно разные понятия. В этих языках преобразование относится к явному или неявному изменению значения из одного формата хранения данных в другой, например, 16-битное целое число в 32-битное целое число. Потребности в хранении могут измениться в результате преобразования, включая возможную потерю точности или усечение. Слово cast , с другой стороны, относится к явному изменению интерпретации битового шаблона .представление значения из одного типа в другой. Например, 32 смежных бита можно рассматривать как массив из 32 логических значений, 4-байтовую строку, 32-битное целое число без знака или значение с плавающей запятой одинарной точности IEEE. Поскольку сохраненные биты никогда не изменяются, программист должен знать детали низкого уровня, такие как формат представления, порядок байтов и требования к выравниванию, чтобы осмысленно привести.

В семействе языков C и ALGOL 68 приведение слова обычно относится к явному преобразованию типа (в отличие от неявного преобразования), вызывая некоторую двусмысленность в отношении того, является ли это повторной интерпретацией битового шаблона или реальным представлением данных. преобразование. Более важным является множество способов и правил, которые применяются к тому, какой тип данных (или класс) определяется указателем, и как указатель может быть скорректирован компилятором в таких случаях, как наследование объекта (класса).

Сравнение языков

C-подобные языки

Неявное преобразование типов

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

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

двойной д ; длинный л ; инт я ; если ( d > я ) d знак равно я ;      если ( я > л ) л знак равно я ;      если ( d == l ) d *= 2 ;      

Хотя d , l и i принадлежат к разным типам данных, они будут автоматически преобразованы в одинаковые типы данных каждый раз, когда выполняется сравнение или присваивание. Это поведение следует использовать с осторожностью, так как могут возникнуть непредвиденные последствия . Данные могут быть потеряны при преобразовании представлений с плавающей запятой в целое число, так как дробные компоненты значений с плавающей запятой будут усечены (округлены до нуля). И наоборот, точность может быть потеряна при преобразовании представлений из целого числа в представление с плавающей запятой, поскольку тип с плавающей запятой может быть неспособен точно представлять целочисленный тип. Например, это может быть IEEE 754 .floatодинарной точности, который не может точно представлять целое число 16777217, в то время как 32-битный целочисленный тип может. Это может привести к неинтуитивному поведению, как показано в следующем коде:

#include <stdio.h> int основной ( недействительный ) { интервал i_value = 16777217 ;    поплавок 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 представляет равенство в последней строке выше. Это странное поведение вызвано неявным преобразованием в float при сравнении с . Преобразование приводит к потере точности, что делает значения равными перед сравнением.i_valuef_value

Важные выводы:

  1. floatto вызывает усечение , т. е. удаление дробной части.int
  2. doubleto вызывает округление цифры.float
  3. longto вызывает отбрасывание избыточных битов более высокого порядка.int
Тип продвижения

Одним из особых случаев неявного преобразования типов является продвижение типов, когда компилятор автоматически расширяет двоичное представление объектов целочисленных типов или типов с плавающей запятой. Продвижение обычно используется с типами, меньшими, чем собственный тип арифметико- логического устройства (ALU) целевой платформы, перед арифметическими и логическими операциями, чтобы сделать такие операции возможными, или более эффективными, если ALU может работать с более чем одним типом. C и C++ выполняют такое преобразование для объектов логического, символьного, широкого символа, перечисления и коротких целых чисел, которые преобразуются в int, а также для объектов типа float, которые преобразуются в double. В отличие от некоторых других преобразований типов, повышения никогда не теряют точности и не изменяют значение, хранящееся в объекте.

В Яве :

интервал  х  =  3 ; двойной  у  =  3,5 ; Система . вне . println ( х  +  у );  // На выходе будет 6,5

Явное преобразование типов

Явное преобразование типов — это преобразование типов, которое явно определено в программе (а не компилятором для неявного преобразования типов). Он определяется пользователем в программе.

двойной да = 3,3 ;   двойной дб = 3,3 ;   двойной постоянный ток = 3,4 ;   int результат = ( int ) da + ( int ) db + ( int ) dc ; // результат == 9 // если бы использовалось неявное преобразование (как с "result = da + db + dc"), результат был бы равен 10        

Существует несколько видов явного преобразования.

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

В объектно-ориентированных языках программирования объекты также могут быть преобразованы вниз  : ссылка базового класса приводится к одному из его производных классов.

С# и С++

В C# преобразование типов может быть выполнено безопасным или небезопасным (т.е. подобным C) способом, первый из которых называется приведением проверенного типа . [8]

Животное  животное  =  новый  кот ();Bulldog  b  =  ( бульдог )  животное ;  // if (animal is Bulldog), stat.type(animal) is Bulldog, иначе исключение b  =  animal  as  Bulldog ;  // если (животное — бульдог), b = (бульдог) животное, иначе b = nullживотное  =  ноль ; b  =  животное  как  бульдог ;  // б == ноль

В C++ аналогичный эффект может быть достигнут с помощью синтаксиса приведения типов в стиле C++ .

Животное * животное = новый кот ;    Bulldog * b = static_cast < Bulldog *> ( животное ); // компилируется, только если Animal или Bulldog являются производными от другого (или того же) b = dynamic_cast < Bulldog *> ( animal ); // если (животное — бульдог), b = (бульдог*) животное, иначе b = nullptr       Bulldog & br = static_cast < Bulldog &> ( * animal ); // то же, что и выше, но будет выдано исключение, если должен быть возвращен nullptr // этого не видно в коде, где обработка исключений исключена animal = nullptr ;       b = dynamic_cast < бульдог *> ( животное ); // б == 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 ... моя_строка  :=  моя_системная_строка

В приведенном выше коде объявлены две строки, по одной каждого типа ( SYSTEM_STRINGэто псевдоним для System.String, совместимый с Eiffel). Поскольку 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 })  ...

Наличие процедуры преобразования делает присвоение:

 моя_строка  :=  моя_системная_строка

семантически эквивалентен:

 создать  мою_строку . make_from_cil  ( my_system_string )

в котором my_stringсоздается как новый объект типа STRING_8с содержимым, эквивалентным содержимому my_system_string.

Чтобы обработать назначение с обратным исходным и целевым исходным кодом:

 моя_системная_строка  :=  моя_строка

класс STRING_8также содержит запрос на преобразование to_cil, который будет создавать System.Stringиз экземпляра STRING_8.

 класс  STRING_8  ...  создать  make_from_cil  ...  преобразовать  make_from_cil  ({ SYSTEM_STRING })  в_cil :  { SYSTEM_STRING }  ...

Назначение:

 моя_системная_строка  :=  моя_строка

тогда становится эквивалентным:

 моя_системная_строка  :=  моя_строка . to_cil

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

Ржавчина

Rust не обеспечивает неявного преобразования типов (приведения) между примитивными типами. Но явное преобразование типов (приведение) может быть выполнено с помощью asключевого слова. [9]

распечатать! ( "1000 как u16: {}" , 1000 как u16 );   

Проблемы с безопасностью

В хакерстве приведение типов — это неправильное использование преобразования типов для временного изменения типа данных переменной по сравнению с тем, как он был изначально определен. [10] Это открывает возможности для хакеров, поскольку при преобразовании типа после того, как переменная «приведена к типу» для преобразования в другой тип данных, компилятор будет рассматривать эту взломанную переменную как новый тип данных для этой конкретной операции. [11]

Смотрите также

  • Понижение
  • Информация о типах во время выполнения#динамическое приведение и приведение Java
  • Введите каламбур

использованная литература

  1. ^ a b c Мехротра, Дирадж (2008). Информатика С. Чанда . стр. 81–83. ISBN 978-8121929844.
  2. ^ Языки программирования — дизайн и конструкции . 2013. с. 35. ISBN 978-9381159415.
  3. ^ б Рейли, Эдвин (2004) . Краткая энциклопедия компьютерных наук . стр.  82, 110 . ISBN 0470090952.
  4. ^ Фентон, Стив (2017). Pro TypeScript: разработка JavaScript в масштабе приложения . стр. XXIII. ISBN 978-1484232491.
  5. ^ «PHP: жонглирование типами — руководство» . php.net . Проверено 27 января 2019 г.
  6. ^ б Олссон, Микаэль (2013) . Краткий справочник по синтаксису C++ . стр. 87–89. ISBN 978-1430262770.
  7. ^ Крузе, Рудольф; Боргельт, Кристиан; Брауне, Кристиан; Мостахим, Саназ; Штайнбрехер, Матиас (16 сентября 2016 г.). Вычислительный интеллект: методологическое введение . п. 269. ИСБН 978-1447172963.
  8. ↑ Mössenböck , Hanspeter (25 марта 2002 г.). «Расширенный C#: проверенные приведения типов» (PDF) . Institut für Systemsoftware, Университет Иоганна Кеплера в Линце, Fachbereich Informatik. п. 5 . Проверено 4 августа 2011 г. в учебнике по С#
  9. ^ "Литье - ржавчина на примере" . doc.rust-lang.org .
  10. ^ Jon Erickson Hacking, 2nd Edition: The Art of Exploitation 2008 1593271441 p51 «Приведение типов — это просто способ временно изменить тип данных переменной, несмотря на то, как он был первоначально определен. Когда переменная преобразуется в другой тип, компилятор в основном сказано обрабатывать эту переменную, как если бы она была новым типом данных, но только для этой операции. Синтаксис приведения типов следующий: (typecast_data_type) variable ..."
  11. ^ Arpita Gopal Magnifying C 2009 8120338618 с. 59 «Из вышеизложенного ясно, что использование приведения типов заключается в том, чтобы сделать переменную одного типа, действующую как другой тип для одной единственной операции. Таким образом, используя эту возможность приведения типов, можно создавать символы ASCII путем преобразования целых это ..."

внешняя ссылка

  • Кастинг в Аде
  • Кастинг на С++
  • Справочное руководство по C++ Почему я ненавижу операторы приведения C++, Дэнни Калев
  • Кастинг на Java
  • Неявные преобразования в C#
  • Неявное приведение типов на Cppreference.com
  • Статическое и реинтерпретационное приведение в C++
  • Повышение и понижение приведения в F#
Получено с " https://en.wikipedia.org/w/index.php?title=Type_conversion&oldid=1038376454 "