Преобразования типов при присваивании
В операциях присваивания тип значения, которое присваивается, преобразуется к типу переменной, получающей это значение. Преобразования при присваивании допускаются даже в тех случаях, когда они влекут за собой потерю информации.
Тип long double ведет себя в преобразованиях аналогично типу double.
Преобразования знаковых целых типов Знаковое целое значение преобразуется к короткому знаковому целому значению (short
signed int) посредством усечения старших битов. Знаковое целое значение преобразуется к длинному знаковому целому значению (long signed int) путем расширения знака влево. Преобразование знаковых целых значений к плавающим значениям происходит путем преобразования к типу long, а затем преобразования к плавающему типу. При этом возможна некоторая потеря точности. При преобразовании знакового целого значения к беззнаковому
целому значению (unsigned int) производится лишь преобразование к размеру беззнакового целого типа, и результат интерпретируется как беззнаковое целое значение.
Правила преобразования знаковых целых типов приведены в таблице 4.2. Предполагается, что тип char по умолчанию является знаковым. Если во время компиляции используется опция, которая изменяет умолчание для типа char со знакового на беззнаковый, то для него выполняется преобразование как для типа unsigned
char (см. таблицу 4.3).
Таблица 4.2.
Преобразование знаковых целых типов
От типа | К типу | Метод |
| ||
char | short | дополнение знаком | |||
char | long | дополнение знаком | |||
char | unsigned char | сохранение битового представления; | |||
char | unsigned short | старший бит теряет функцию знакового бита дополнение знаком до short; преобразование short в unsigned short | |||
char | unsigned long | дополнение знаком до long; преобразование long в unsigned long | |||
char | float | дополнение знаком до long; преобразование long к float | |||
char | double | дополнение знаком до long; преобразование long к double | |||
short | char | сохранение младшего байта | |||
short | long | дополнение знаком | |||
short | unsigned char | сохранение младшего байта | |||
short | unsigned short | сохранение битового представления; старший бит теряет функцию знакового бита | |||
short | unsigned long | дополнение знаком до long; преобразование long в unsigned long | |||
short | float | дополнение знаком до long; преобразование long к float | |||
short | double | дополнение знаком до long; преобразование long к double | |||
long | char | сохранение младшего байта | |||
long | short | сохранение младшего слова | |||
long | unsigned char | сохранение младшего байта | |||
long | unsigned short | сохранение младшего слова | |||
long | unsigned long | сохранение битового представления; старший бит теряет функцию знакового бита | |||
long | float | представляется как float; возможна некоторая потеря точности | |||
long | double | представляется как double; возможна некоторая потеря точности |
Примечание. В СП MSC и СП ТС тип int
эквивалентен типу short и преобразование для типа int производится как для типа short. В некоторых реализациях языка Си тип int эквивалентен типу long и преобразование для типа int
производится как для типа long.
Преобразование беззнаковых целых типов
Беззнаковое целое значение преобразуется к короткому беззнаковому целому значению или короткому знаковому целому значению путем усечения старших битов. Беззнаковое целое значение преобразуется к длинному беззнаковому целому значению или длинному знаковому целому значению путем дополнения нулями слева. Беззнаковое целое значение преобразуется к значению с плавающей точкой путем преобразования к типу long, а затем преобразования значения типа long к значению с плавающей точкой.
Если беззнаковое целое значение преобразуется к знаковому целому значению того же размера, то битовое представление не меняется. Однако, если старший (знаковый) бит был установлен в единицу, представляемое значение изменится.
Правила преобразования беззнаковых целых типов приведены в таблице 4.3.
Таблица 4.3.
Преобразование беззнаковых целых типов
От типа |
К типу |
Метод |
unsigned char |
char |
сохранение битового представления; старший бит становится знаковым |
unsigned char |
short |
дополнение нулевыми битами |
unsigned char |
long |
дополнение нулевыми битами |
unsigned char |
unsigned short |
дополнение нулевыми битами |
unsigned char |
unsigned long |
дополнение нулевыми битами |
unsigned char |
float |
дополнение нулевыми битами до long; преобразование long к float |
unsigned char |
double |
дополнение нулевыми битами до long; преобразование long к double |
unsigned short |
char |
сохранение младшего байта |
unsigned short |
short |
сохранение битового представления; старший бит становится знаковым |
unsigned short |
long |
дополнение нулевыми битами |
unsigned short |
unsigned char |
сохранение младшего байта |
unsigned short |
unsigned long |
дополнение нулевыми битами |
unsigned short |
float |
дополнение нулевыми битами до long; преобразование long к float |
unsigned short |
double |
дополнение нулевыми битами до long; преобразование long к double |
unsigned long |
char |
сохранение младшего байта |
unsigned long |
short |
сохранение младшего слова |
unsigned long |
long |
сохранение битового представления; старший бит становится знаковым |
unsigned long |
unsigned char |
сохранение младшего байта |
unsigned long |
unsigned short |
сохранение младшего слова |
unsigned long |
float |
преобразование к long; преобразование long к float |
unsigned long |
double |
преобразование к long; преобразование long к double (в версии 5 СП MSC это преобразование производится напрямую, без промежуточного типа long) |
Примечание. В СП MSC и СП ТС тип unsigned int эквивалентен типу unsigned short и преобразование для типа unsigned int
производится как для типа unsigned short. В некоторых реализациях языка Си тип unsigned int эквивалентен типу unsigned
long и преобразование для типа int
производится как для типа unsigned long.
Преобразование плавающих типов Значения типа float
преобразуются к типу double без потери точности. Значения типа double при преобразовании к типу float представляются с некоторой потерей точности. Однако если порядок значения типа double слишком велик для представления экспонентой
значения типа float, то происходит потеря значимости, о чем сообщается во время выполнения.
Значения с плавающей точкой преобразуются к целым типам в два приема: сначала производится преобразование к типу long, а затем преобразование этого значения типа long к требуемому типу. Дробная часть плавающего значения отбрасывается при преобразовании к long; если полученное значение слишком велико для типа long, то результат преобразования не определен. Правила преобразования плавающих типов приведены в таблице 4.4.
Таблица 4.4.
От типа |
К типу |
Метод |
float |
char |
преобразование к long; преобразование long к char |
float |
short |
преобразование к long; преобразование long к short |
float |
long |
усечение дробной части; результат не определен, если он слишком велик для представления типом long |
float |
unsigned short |
преобразование к long; преобразование long к unsigned short |
float |
unsigned long |
преобразование к long; преобразование long к unsigned long |
float |
double |
дополнение мантиссы нулевыми битами справа |
double |
char |
преобразование к float; преобразование float к char |
double |
short |
преобразование к float; преобразование float к short |
double |
long |
усечение дробной части; результат не определен, если он слишком велик для представления типом long |
double |
unsigned short |
преобразование к long; преобразование long к unsigned short |
double |
unsigned long |
преобразование к long; преобразование long к unsigned long |
double |
float |
усечение младших битов мантиссы; возможна потеря точности; если значение слишком велико для представления типом float, то результат преобразования не определен |
Преобразование указателей
Указатель на значение одного типа может быть преобразован к указателю на значение другого типа. Результат может, однако, оказаться неопределенным из-за отличий в требованиях к выравниванию объектов разных типов и в размере памяти, занимаемом различными типами.
Указатель при объявлении всегда ассоциируется с некоторым типом. В частности, это может быть тип void. Указатель на void можно преобразовывать к указателю на любой тип, и обратно. Указателям на некоторый тип можно присваивать адреса объектов другого типа, однако компилятор выдаст предупреждающее сообщение, если только это не указатель на тип void.
Указатели на любые типы данных могут быть преобразованы к указателям на функции, и обратно. Однако в СП MSC для того, чтобы присвоить указатель на данные указателю на функцию (или наоборот), необходимо выполнить явное приведение его типа.
Специальные ключевые слова near, far, huge позволяют модифицировать формат и размер указателей в программе. Компилятор учитывает принятый в выбранной модели памяти размер указателей и может в некоторых случаях неявно производить соответствующие преобразования адресных значений. Так, передача указателя в качестве аргумента функции может вызвать неявное преобразование его размера к большему из следующих двух значений:
—принятому по умолчанию размеру указателя для действующей модели памяти (например, в средней модели указатель на данные имеет тип near);
—размеру типа аргумента.
Если задано предварительное объявление функции, в котором указан явно тип аргумента-указателя, в т.ч. с модификаторами near, far, huge, то будет преобразование именно к этому типу.
Указатель может быть преобразован к значению целого типа. Метод преобразования зависит от размера указателя и размера целого типа следующим образом:
—если указатель имеет тот же самый или меньший размер, чем целый тип, то указатель преобразуется по тем же правилам, что и беззнаковое целое;
—если размер указателя больше, чем размер целого типа, то указатель сначала преобразуется к указателю того же размера, что и целый тип, а затем преобразуется к целому типу.
Значение целого типа может быть преобразовано к указателю по следующим правилам. Если целый тип имеет тот же самый размер, что и указатель, то производится преобразование к указателю без изменения в представлении. Если же размер целого типа отличен от размера указателя, то целый тип сначала преобразуется к целому типу, размер которого совпадает с размером указателя, используя правила преобразования, приведенные в таблицах 4.2 и 4.3. Затем полученному значению присваивается тип указатель.
Преобразования других типов
Из определения перечислимого типа следует, что его значения имеют тип int. Поэтому преобразования к перечислимому типу и из него осуществляются так же, как для типа int.
Недопустимы преобразования объектов типа структура или объединение.
Тип void не имеет значения по определению. Поэтому он не может быть преобразован к другому типу, и никакое значение не может быть преобразовано к типу void путем присваивания. Тем не менее, значение может быть явно преобразовано операцией приведения типа к типу void (см. раздел 4.7.2).