Как поменять тип переменной в c
Перейти к содержимому

Как поменять тип переменной в c

  • автор:

Как поменять тип переменной в c

Если в арифметических операциях участвуют значения разных типов, то компилятор неявно пытается привести их к одному типу. Кроме того, когда мы присваиваем переменной какое-либо значение, это значение всегда приводится к типу переменной. Например:

Переменной d, которая представляет тип int, присваивается значение типа char, поэтому компилятор выполняет приведение значения от типа char к типу int.

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

Рассмотрим, какие преобразования применяет компилятор при арифметических операциях:

Если один из операндов имеет тип long double , то второй операнд тоже будет преобразован в тип long double

Если предыдущий пункт не выполняется и если один из операндов имеет тип double , то второй операнд тоже будет преобразован к типу double

Если предыдущий пункт не выполняется и если один из операндов имеет тип float , то второй операнд тоже будет преобразован к типу float

Если предыдущий пункт не выполняется и если один из операндов имеет тип unsigned long int , то второй операнд тоже будет преобразован к типу unsigned long int

Если предыдущий пункт не выполняется и если один из операндов имеет тип long , то второй операнд тоже будет преобразован к типу long

Если предыдущий пункт не выполняется и если один из операндов имеет тип unsigned , то второй операнд тоже будет преобразован к типу unsigned

Если предыдущий пункт не выполняется то оба операнда приводятся к типу int

В выражении number1 + number2 число number2 представляет тип double , поэтому число number1 будет автоматически приводиться к числу double. И результат операции сложения также будет представлять тип double .

Операция преобразования

С помощью специальной операции преобразования мы можем явным образом привести данные к нужному типу. Например:

В выражении int c = a / b; результат деления будет целочисленный — 2, при котором дробная часть будет отброшена, так как оба операнда операции представляют целые числа.

В выражении double d = a / b; результат деления будет представлять вещественное число — 2.00000, но так как оба операнда являются целыми числами, то опять же результат операции будет представлять целое число 2, и только поле выполнения деления произойдет присвоение результата переменной d с приведением значения 2 от типа int к типу double.

В выражении double e = (double)a / (double)b применяется явное преобразование данных к типу double, поэтому и результат деления будет представлять вещественное число — 2.50000.

Для выполнения операции приведении в скобках указывается тот тип, к которому надо привести значение:

В ряде случаев преобразования сопровождаются потерей информации, например, когда числа большей разрядности (скажем размером 4 байт) получаем число меньшей разрядности (например, в 2 байта). Без потери информации проходят следующие цепочки преобразований:

char -> short -> int -> long

unsigned char -> unsigned short -> unsigned int -> unsigned long

float -> double -> long double

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

Здесь две ситуации небезопасных преобразований. В первом случае число типа int , которое равно 300, присваивается переменной типа char . В итоге переменная code будет равна 44. Почему? Число 300 в двоичной системе:

Оставляем только первый младший байт:

И у нас получается число 44 в десятичной системе.

Во втором случае число 100000 (которое по умолчанию представляет тип int ), усекается до разрядности типа short — до двух байт.

Изменение типа данных переменной

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

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

Удобнее всего воспользоваться указателем типа void*.

Дизайн сайта / логотип © 2023 Stack Exchange Inc; пользовательские материалы лицензированы в соответствии с CC BY-SA . rev 2023.9.4.43609

Нажимая «Принять все файлы cookie» вы соглашаетесь, что Stack Exchange может хранить файлы cookie на вашем устройстве и раскрывать информацию в соответствии с нашей Политикой в отношении файлов cookie.

Еще раз про приведение типов в языке С++ или расстановка всех точек над cast


Этот пост попытка кратко оформить все, что я читал или слышал из разных источников про операторы приведения типов в языке C++. Информация ориентирована в основном на тех, кто изучает C++ относительно недолго и, как мне кажется, должна помочь понять cпецифику применения данных операторов. Старожилы и гуру С++ возможно помогут дополнить или скорректировать описанную мной картину. Всех интересующихся приглашаю под кат.

Приведение типов в стиле языка C (C-style cast)

Приведение типов в стиле языка C может привести выражение любого типа к любому другому типу данных (исключение это приведение пользовательских типов по значению, если не определены правила их приведения, а также приведение вещественного типа к указателю или наоборот). К примеру, unsigned int может быть преобразован к указателю на double. Данный метод приведения типов может быть использован в языке C++. Однако, метод приведения типов в стиле языка C не делает проверки типов на совместимость, как это могут сделать static_cast и dynamic_cast на этапе компиляции и на этапе выполнения соответственно. При этом все, что умеют const_cast и reinterpret_cast данный метод приведения типов делать может.

Общий вид приведения:

(new_type)exp

, где new_type – новый тип, к которому приводим, а exp – выражение, которое приводится к новому типу.

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

const_cast

Оператор приведения const_cast удаляет или добавляет квалификаторы const и volatile с исходного типа данных (простые типы, пользовательские типы, указатели, ссылки). Например, был const int, а после преобразования стал int или наоборот. Квалификаторы const и volatile называют cv-квалификаторы (cv-qualifiers). Данные квалификаторы указываются перед именами типов. Как ни трудно догадаться квалификатор const задает константность, т.е. защищает переменную от изменения. Квалификатор volatile говорит о том, что значение переменной может меняться без явного выполнения присваивания. Это обеспечивает защиту от оптимизации компилятором операций с данной переменной.

Общий вид приведения:

const_cast<new_type>(exp)

Дополнительный пример от пользователя 5nw

Квалификаторы const и volatile можно удалить или добавить только с помощью оператора приведения const_cast и приведения типов в стиле языка C. Другие операторы приведения типов не влияют на квалификаторы const и volatile (reinterpret_cast, static_cast, dynamic_cast).

reinterpret_cast

Оператор приведения reinterpret_cast используется для приведения несовместимых типов. Может приводить целое число к указателю, указатель к целому числу, указатель к указателю (это же касается и ссылок). Является функционально усеченным аналогом приведения типов в стиле языка С. Отличие состоит в том, что reinterpret_cast не может снимать квалификаторы const и volatile, а также не может делать небезопасное приведение типов не через указатели, а напрямую по значению. Например, переменную типа int к переменной типа double привести при помощи reinterpret_cast нельзя.

Общий вид приведения:

reinterpret_cast<new_type>(exp)

static_cast

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

Общий вид приведения:

static _cast<new_type>(exp)

dynamic_cast

Оператор приведения dynamic_cast применяется для полиморфного приведения типов на этапе выполнения программы (класс считается полиморфным, если в нем есть хотя бы одна виртуальная функция). Если указатель, подлежащий приведению, ссылается на объект результирующего класса или объект класса производный от результирующего то приведение считается успешным. То же самое для ссылок. Если приведение невозможно, то на этапе выполнения программы будет возвращен NULL, если приводятся указатели. Если приведение производится над ссылками, то будет сгенерировано исключение std::bad_cast. Несмотря на то, что dynamic_cast предназначен для приведения полиморфных типов по иерархии наследования, он может быть использован и для обычных неполиморфных типов вверх по иерархии. В этом случае ошибка будет получена на этапе компиляции. Оператор приведения dynamic_cast может приводить указатель на полиморфный тип к указателю на void, но не может приводить указатель на void к другому типу. Способность dynamic_cast приводить полиморфные типы обеспечивается системой RTTI (Run-Time Type Identification), которая позволяет идентифицировать тип объекта в процессе выполнения программы. При множественном наследовании dynamic_cast может вернуть указатель не на исходный объект, а на его подобъект.

C Урок 14. Преобразование типов

На данном уроке мы поговорим о преобразовании типов данных в процессе работы программы из одного типа в другой.

Конечно, в идеальном случае, желательно, чтобы программа была построена таким образом чтобы лишний раз избегать всякого рода преобразований и использовать везде данные нужного типа. Но не всегда так получается и преобразование типа в ряде случаев просто необходимо. Например, мы складываем значения двух переменных типа unsigned short и, по идее у нас результат тоже должен присваиваться переменной типа unsigned short. Но мы не уверены в том, что этот результат уместится в такой тип, например, мы захотим сложить числа 65535 и 65534. Поэтому здесь без преобразования не обойтись. И таких ситуаций огромное множество, поэтому мы должны знать как происходит преобразование типов автоматически, а также как мы можем этим процессом управлять. Думаю, данный урок даст хоть и не полную картину преобразований типов, но, тем не менее, внесёт некоторую ясность в данную тему.

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

Если операнды некоторой операции принадлежат различным типам, то они автоматически приводятся к определённому общему типу. А к какому именно, существует ряд правил.

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

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

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

  • long double
  • double;
  • float;
  • unsigned long long;
  • long long;
  • unsigned long;
  • long;
  • unsigned int;
  • int

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

В операциях присваивания также может происходить неявное преобразование типов данных.

Например, если мы хотим значение 8-байтового типа присвоить переменной 4-байтового типа, неважно, целого типа эти данные или нет, то при этом произойдёт неявное преобразование к 4-байтовому типу, при этом старшие 4 байта отбрасываются. Это считается небезопасным приведением типов, когда возможна потеря информации.

Может быть и наоборот, если мы хотим значение 4-байтового типа присвоить переменной 8-байтового типа. Также произойдёт неявное преобразование и, наоборот, 4 старших байта добавятся и заполнятся нулями. Это будет уже безопасное приведение типа и при этом целостность информации не страдает.

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

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

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

int i;

char c = 45;

i = ( int )c;

В данном случае значение переменной c явно преобразовывается к типу данных int, а затем уже в преобразованном виде присваивается переменной i.

Вот ещё несколько примеров явного преобразования типов данных

sqrt(( double ) n)

float f_res = ( float ) i / ( float ) j;

double f_res = ( double )(( float ) i / ( float ) j);

Давайте теперь поэкспериментируем с преобразованием типов данных на практике в реальном коде.

Проект сделаем из проекта MYPROG13 прошлого занятия и имя ему было присвоено MYPROG14.

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

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