Ghtj hfpjdfybt nbgjd c

В программировании нередко значения переменных одного типа присваиваются переменным другого типа. Например, в приведенном ниже фрагменте кода целое значение типа int присваивается переменной с плавающей точкой типа float:

Если в одной операции присваивания смешиваются совместимые типы данных, то значение в правой части оператора присваивания автоматически преобразуется в тип, указанный в левой его части. Поэтому в приведенном выше фрагменте кода значение переменной i сначала преобразуется в тип float, а затем присваивается переменной f. Но вследствие строгого контроля типов далеко не все типы данных в C# оказываются полностью совместимыми, а следовательно, не все преобразования типов разрешены в неявном виде. Например, типы bool и int несовместимы. Правда, преобразование несовместимых типов все-таки может быть осуществлено путем приведения. Приведение типов, по существу, означает явное их преобразование.

Автоматическое преобразование типов

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

  • оба типа совместимы
  • диапазон представления чисел целевого типа шире, чем у исходного типа

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

Числовые типы, как целочисленные, так и с плавающей точкой, вполне совместимы друг с другом для выполнения расширяющих преобразований. Рассмотрим пример:

Обратите внимание на то, что метод Sum() ожидает поступления двух параметров типа int. Тем не менее, в методе Main() ему на самом деле передаются две переменных типа short. Хотя это может показаться несоответствием типов, программа будет компилироваться и выполняться без ошибок и возвращать в результате, как и ожидалось, значение 25.

Причина, по которой компилятор будет считать данный код синтаксически корректным, связана с тем, что потеря данных здесь невозможна. Поскольку максимальное значение (32767), которое может содержать тип short, вполне вписывается в рамки диапазона типа int (максимальное значение которого составляет 2147483647), компилятор будет неявным образом расширять каждую переменную типа short до типа int. Формально термин "расширение" применяется для обозначения неявного восходящего приведения (upward cast), которое не приводит к потере данных.

Приведение несовместимых типов

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

Здесь целевой_тип обозначает тот тип, в который желательно преобразовать указанное выражение.

Если приведение типов приводит к сужающему преобразованию, то часть информации может быть потеряна. Например, в результате приведения типа long к типу int часть информации потеряется, если значение типа long окажется больше диапазона представления чисел для типа int, поскольку старшие разряды этого числового значения отбрасываются. Когда же значение с плавающей точкой приводится к целочисленному, то в результате усечения теряется дробная часть этого числового значения. Так, если присвоить значение 1,23 целочисленной переменной, то в результате в ней останется лишь целая часть исходного числа (1), а дробная его часть (0,23) будет потеряна. Давайте рассмотрим пример:

Результатом работы данной программы будет:

Обратите внимание, что переменная i1 корректно преобразовалась в тип short, т.к. ее значение входит в диапазон этого типа данных. Преобразование переменной dec в тип int вернуло целую часть этого числа. Преобразование переменной i2 вернуло значение переполнения 18964 (т.е. 84500 – 2*32768).

Перехват сужающих преобразований данных

В предыдущем примере приведение переменной i2 к типу short не является приемлемым, т.к. возникает потеря данных. Для создания приложений, в которых потеря данных должна быть недопустимой, в C# предлагаются такие ключевые слова, как checked и unchecked, которые позволяют гарантировать, что потеря данных не окажется незамеченной.

По умолчанию, в случае, когда не предпринимается никаких соответствующих исправительных мер, условия переполнения (overflow) и потери значимости (underflow) происходят без выдачи ошибки. Обрабатывать условия переполнения и потери значимости в приложении можно двумя способами. Это можно делать вручную, полагаясь на свои знания и навыки в области программирования.

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

К счастью, в C# предусмотрено ключевое слово checked. Если оператор (или блок операторов) заключен в контекст checked, компилятор C# генерирует дополнительные CIL-инструкции, обеспечивающие проверку на предмет условий переполнения, которые могут возникать в результате сложения, умножения, вычитания или деления двух числовых типов данных.

В случае возникновения условия переполнения во время выполнения будет генерироваться исключение System.OverflowException. Давайте рассмотрим пример, в котором будем передавать в консоль значение исключения:

Результат работы данной программы:

Настройка проверки на предмет возникновения условий переполнения в масштабах проекта

Если создается приложение, в котором переполнение никогда не должно проходить незаметно, может выясниться, что обрамлять ключевым словом checked приходится раздражающе много строк кода. На такой случай в качестве альтернативного варианта в компиляторе C# поддерживается флаг /checked. При активизации этого флага проверки на предмет возможного переполнения будут автоматически подвергаться все имеющиеся в коде арифметические операции, без применения для каждой из них ключевого слова checked. Обнаружение переполнения точно так же приводит к генерации соответствующего исключения во время выполнения.

Читайте также:  Dvb t2 приставка для смартфона

Для активизации этого флага в Visual Studio 2010 необходимо открыть страницу свойств проекта, перейти на вкладку Build (Построение), щелкнуть на кнопке Advanced (Дополнительно) и в открывшемся диалоговом окне отметить флажок Check for arithmetic overflow/underflow (Проверять арифметические переполнения и потери точности):

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

Итак, чтобы подвести итог по использованию в C# ключевых слов checked и unchecked, следует отметить, что по умолчанию арифметическое переполнение в исполняющей среде .NET игнорируется. Если необходимо обработать отдельные операторы, то должно использоваться ключевое слово checked, а если нужно перехватывать все связанные с переполнением ошибки в приложении, то понадобится активизировать флаг /checked. Что касается ключевого слова unchecked, то его можно применять при наличии блока кода, в котором переполнение является допустимым (и, следовательно, не должно приводить к генерации исключения во время выполнения).

Роль класса System.Convert

В завершении темы преобразования типов данных стоит отметить, что в пространстве имен System имеется класс Convert, который тоже может применяться для расширения и сужения данных:

Обновл. 19 Апр 2019 |

Из предыдущего урока мы уже знаем, что компилятор в определённых случаях выполняет неявное преобразование типов данных.

Вступление

Когда вы хотите изменить один тип данных на другой, более крупный (по размеру/диапазону), то неявное преобразование является хорошим вариантом.

Но многие начинающие программисты часто пытаются сделать что-то вроде следующего: float x = 11 / 3; . Однако, поскольку 11 и 3 являются целыми числами, то никакое числовое расширение не происходит. Выполняется целочисленное деление 11 / 3 , результатом которого будет значение 3 , которое затем неявно преобразуется в 3.0 и присвоится переменной x !

В случае, когда вы используете литералы (такие как 11 или 3), замена одного или обоих целочисленных литералов значением типа с плавающей точкой (11.0 или 3.0) приведёт к конвертации обоих операндов в значения типа с плавающей точкой и выполнится деление типа с плавающей точкой.

Но что будет, если использовать переменные? Например:

Значением переменной x будет 3 . Как сообщить компилятору, что мы хотим использовать деление типа с плавающей точкой вместо целочисленного деления? Правильно! Использовать один из операторов явного преобразования типов данных, чтобы указать компилятору выполнить явное преобразование.

Операторы явного преобразования типов данных

В C++ есть 5 типов операторов casts (или ещё «операторов явного преобразования типов»):

В этом уроке мы рассмотрим C-style cast и static_cast. dynamic_cast мы будем рассматривать, когда дойдём до указателей и наследования. const_cast и reinterpret_cast следует избегать вообще, потому что они полезны только в редких случаях и могут создать немало проблем, если их использовать неправильно.

Правило: Избегайте использования const_cast и reinterpret_cast, если у вас нет на это веской причины.

C-style cast

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

В программе выше мы используем круглые скобки, чтобы сообщить компилятору преобразовать переменную i1 (типа int) в тип float. Поскольку i1 станет типа float, то i2 затем автоматически преобразуется в тип float также и выполнится деление типа с плавающей точкой!

C++ также позволяет использовать этот оператор и следующим образом:

C-style cast не проверяется компилятором во время компиляции, поэтому может быть неправильно использован, например: при конвертации типов const или изменении типов данных, без учёта их диапазонов (что приведёт к переполнению).

Следовательно, C-style cast лучше не использовать.

Правило: Не используйте C-style cast.

Оператор static_cast

В C++ есть ещё один оператор явного преобразования типов данных — static_cast. Ранее, в уроке о символьном типе данных, мы уже использовали static_cast для конвертации переменной типа char в тип int, выводя вместо символа целое число:

Оператор static_cast лучше всего использовать для конвертации одного фундаментального типа данных в другой:

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

Использование операторов явного преобразования в неявном преобразовании

Если вы будете выполнять небезопасные неявные преобразования типов данных, то компилятор будет жаловаться. Например:

Конвертация переменной типа int (4 байта) в тип char (1 байт) потенциально опасна — компилятор выдаст предупреждение. Чтобы сообщить ему, что вы намеренно делаете что-то, что потенциально опасно (но хотите сделать это в любом случае), используйте оператор static_cast:

В следующем случае компилятор будет жаловаться, что конвертация из double в int может привести к потере данных:

Чтобы сообщить компилятору, что мы сознательно хотим сделать это:

Заключение

Преобразования типов данных следует избегать, если это вообще возможно, поскольку всякий раз, когда выполняется подобное изменение, есть вероятность возникновения непредвиденных проблем. Но очень часто случаются ситуации, когда этого не избежать. Поэтому в таких случаях лучше использовать оператор static_cast вместо C-style cast.

В чём разница между явным и неявным преобразованием типов данных?

Ответ

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

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

Читайте также:  Anno 1404 как правильно строить город

За репост +20 к карме и моя благодарность!

Урок №55. Неявное преобразование типов данных

Комментариев: 8

прошло без всяких проблем.

Смотря что Вы подразумеваете под проблемой)
Если под проблемой Вы подразумеваете ошибку компиляции или рантайма, то да, код корректен и должен отработать, так что не удивительно, что оно "прошло без всяких проблем", однако, в действительности, проблема есть. Вам повезло со значениями и 90 делится на 3.6 без остатка, потому имеем 25, но подели Вы 90 на 3.7 (24.32…) или 3.5 (25.71…), или ещё на какое число, данный код выдаст Вам, для 3.7 (24), а для 3.5 (25), хотя остаток есть.

Во второй строке Вы неявно приводите i к типу double при делении, за счёт дробного знаменателя, получаете вещественный результат (по сути, временный rvalue объект, с типом double), который, затем, пытаетесь присвоить переменной, тип которой как был int, так и остался, а, значит, будет произведено приведение вещественного результата к типу int.
Если Вы так и хотели — работать с целочисленным значением, то всё хорошо, в противном же случае стоит сменить тип i, либо, если по какой то причине этого делать не хочется, создать буфер, который будет хранить вещественный результат.
Также, Вашу вторую строчку можно сократить до i /= 3.6;

пользоваться фокусом с числовыми литералами (11.0 / 3.0 или a / 2.0) также крайне не желательно. При некоторых настройках оптимизации такое деление все равно будет произведено в целых числах

Оплячки-опляпапапашныя! Александр, а ну, пожалуйста, с этого момента по-подробнее (и что следует предпринять, чтобы не нарваться на " такое деление все равно будет произведено в целых числах " ?)

В статье же все есть :)))

Часто пользуются фокусом для вещественного деления:

Поскольку код C# является статически типизированным во время компиляции, после объявления переменной ее нельзя объявить повторно или назначить ей значения другого типа, если этот тип невозможно неявно преобразовать в тип переменной. Because C# is statically-typed at compile time, after a variable is declared, it cannot be declared again or assigned a value of another type unless that type is implicitly convertible to the variable’s type. Например, string невозможно неявно преобразовать в int . For example, the string cannot be implicitly converted to int . Поэтому после объявления i как int нельзя назначить ей строку "Hello", как показано в следующем коде: Therefore, after you declare i as an int , you cannot assign the string "Hello" to it, as the following code shows:

Тем не менее иногда может потребоваться скопировать значение в переменную или параметр метода другого типа. However, you might sometimes need to copy a value into a variable or method parameter of another type. Например, может потребоваться передать целочисленную переменную в метод, параметр которого имеет тип double . For example, you might have an integer variable that you need to pass to a method whose parameter is typed as double . Или может понадобиться присвоить переменную класса переменной типа интерфейса. Or you might need to assign a class variable to a variable of an interface type. Такого рода операции называются преобразованиями типа. These kinds of operations are called type conversions. В C# можно выполнять следующие виды преобразований. In C#, you can perform the following kinds of conversions:

Неявные преобразования. Специальный синтаксис не требуется, так как преобразование является строго типизированным и данные не будут потеряны. Implicit conversions: No special syntax is required because the conversion is type safe and no data will be lost. Примеры включают преобразования из меньших в большие целочисленные типы и преобразования из производных классов в базовые классы. Examples include conversions from smaller to larger integral types, and conversions from derived classes to base classes.

Явные преобразования (приведения) . Для явных преобразований требуется оператор приведения () . Explicit conversions (casts): Explicit conversions require the cast operator () . Приведение требуется, если в ходе преобразования данные могут быть утрачены или преобразование может завершиться сбоем по другим причинам. Casting is required when information might be lost in the conversion, or when the conversion might not succeed for other reasons. Типичными примерами являются числовое преобразование в тип с меньшей точностью или меньшим диапазоном и преобразование экземпляра базового класса в производный класс. Typical examples include numeric conversion to a type that has less precision or a smaller range, and conversion of a base-class instance to a derived class.

Пользовательские преобразования. Такие преобразования выполняются специальными методами, которые можно определить для включения явных и неявных преобразований между пользовательскими типами без связи "базовый класс — производный класс". User-defined conversions: User-defined conversions are performed by special methods that you can define to enable explicit and implicit conversions between custom types that do not have a base class–derived class relationship. Дополнительные сведения см. в разделе Операторы пользовательского преобразования. For more information, see User-defined conversion operators.

Преобразования с использованием вспомогательных классов. Чтобы выполнить преобразование между несовместимыми типами, например целыми числами и объектами System.DateTime или шестнадцатеричными строками и массивами байтов, можно использовать классы System.BitConverter и System.Convert, а также методы Parse встроенных числовых типов, такие как Int32.Parse. Conversions with helper classes: To convert between non-compatible types, such as integers and System.DateTime objects, or hexadecimal strings and byte arrays, you can use the System.BitConverter class, the System.Convert class, and the Parse methods of the built-in numeric types, such as Int32.Parse. Дополнительные сведения см. в разделе Практическое руководство. преобразованию массива байтов в значение типа int, преобразованию строки в число и преобразованию из шестнадцатеричных строк в числовые типы. For more information, see How to: Convert a byte Array to an int, How to: Convert a String to a Number, and How to: Convert Between Hexadecimal Strings and Numeric Types.

Читайте также:  Старый ноутбук тормозит что делать

Неявные преобразования Implicit conversions

Для встроенных числовых типов неявное преобразование можно выполнить, если сохраняемое значение может уместиться в переменной без усечения или округления. For built-in numeric types, an implicit conversion can be made when the value to be stored can fit into the variable without being truncated or rounded off. При использовании целочисленных типов это означает, что диапазон исходного типа является надлежащим подмножеством диапазона для целевого типа. For integral types, this means the range of the source type is a proper subset of the range for the target type. Например, переменная типа long (64-разрядное целое число) может хранить любое значение, которое может хранить переменная int (32-разрядное целое число). For example, a variable of type long (64-bit integer) can store any value that an int (32-bit integer) can store. В следующем примере компилятор неявно преобразует значение num справа в тип long перед назначением bigNum . In the following example, the compiler implicitly converts the value of num on the right to a type long before assigning it to bigNum .

Полный список всех неявных числовых преобразований см. в разделе Таблица неявных числовых преобразований в статье Встроенные числовые преобразования. For a complete list of all implicit numeric conversions, see the Implicit numeric conversions section of the Built-in numeric conversions article.

Для ссылочных типов неявное преобразование всегда предусмотрено из класса в любой из его прямых или косвенных базовых классов или интерфейсов. For reference types, an implicit conversion always exists from a class to any one of its direct or indirect base classes or interfaces. Никакой специальный синтаксис не требуется, поскольку производный класс всегда содержит все члены базового класса. No special syntax is necessary because a derived class always contains all the members of a base class.

Явные преобразования Explicit conversions

Тем не менее если преобразование нельзя выполнить без риска потери данных, компилятор требует выполнения явного преобразования, которое называется приведением. However, if a conversion cannot be made without a risk of losing information, the compiler requires that you perform an explicit conversion, which is called a cast. Приведение — это способ явно указать компилятору, что необходимо выполнить преобразование и что вам известно, что может произойти потеря данных. A cast is a way of explicitly informing the compiler that you intend to make the conversion and that you are aware that data loss might occur. Чтобы выполнить приведение, укажите тип, в который производится приведение, в круглых скобках перед преобразуемым значением или переменной. To perform a cast, specify the type that you are casting to in parentheses in front of the value or variable to be converted. В следующей программе выполняется приведение типа double в int. Программа не будет компилироваться без приведения. The following program casts a double to an int. The program will not compile without the cast.

Полный список всех поддерживаемых явных числовых преобразований см. в разделе Таблица явных числовых преобразований в статье Встроенные числовые преобразования. For a complete list of supported explicit numeric conversions, see the Explicit numeric conversions section of the Built-in numeric conversions article.

Для ссылочных типов явное приведение является обязательным, если необходимо преобразовать базовый тип в производный тип: For reference types, an explicit cast is required if you need to convert from a base type to a derived type:

Операция приведения между ссылочными типами не меняет тип времени выполнения базового объекта; изменяется только тип значения, который используется в качестве ссылки на этот объект. A cast operation between reference types does not change the run-time type of the underlying object; it only changes the type of the value that is being used as a reference to that object. Дополнительные сведения см. в разделе Полиморфизм. For more information, see Polymorphism.

Исключения преобразования типов во время выполнения Type conversion exceptions at run time

В некоторых преобразованиях ссылочных типов компилятор не может определить, будет ли приведение допустимым. In some reference type conversions, the compiler cannot determine whether a cast will be valid. Есть вероятность, что правильно скомпилированная операция приведения завершится сбоем во время выполнения. It is possible for a cast operation that compiles correctly to fail at run time. Как показано в следующем примере, приведение типа, завершившееся сбоем во время выполнения, вызывает исключение InvalidCastException. As shown in the following example, a type cast that fails at run time will cause an InvalidCastException to be thrown.

C# предоставляет оператор is, чтобы можно было проверить совместимость перед фактическим выполнением приведения. C# provides the is operator to enable you to test for compatibility before actually performing a cast. Дополнительные сведения см. в статье Практическое руководство. Безопасное приведение с помощью сопоставления шаблонов и операторы is и as. For more information, see How to: safely cast using pattern matching and the as and is operators.

Спецификация языка C# C# language specification

Дополнительные сведения см. в разделе Преобразования спецификация языка C#. For more information, see the Conversions section of the C# language specification.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock detector