Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
PYaVU_s.doc
Скачиваний:
44
Добавлен:
24.02.2016
Размер:
665.09 Кб
Скачать
    1. Побочные эффекты

Побочные эффекты - это изменения состояния машины, которые возникают в результате вычисления выражений. Они имеют место всякий раз, когда изменяется значение переменной. Любая операция присваивания вызывает побочный эффект, и любой вызов функции, который содержит операцию присваивания, имеет побочные эффекты.

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

Например, побочный эффект имеет место в следующем вызове функции:

add ( i + 1, i = j +2)

Аргументы вызова функции могут быть вычислены в любом порядке. Выражение i + 1 может быть вычислено перед i=j+2, или наоборот, с различным результатом в каждом случае.

Унарные операции инкремента и декремента включают присваивание и могут быть причиной побочных эффектов, как это показано в следующем примере:

d=0

a=b++=c++=d++;

Значение a непредсказуемо. Значение d (инициализируется нулем), могло быть присвоено c, затем b и затем a, прежде чем любая из переменных была бы инкрементирована. В этом случае a должно было бы быть эквивалентно нулю.

Второй способ вычисления этого выражения начинается вычислением операнда c++=d++. Значение d (инициализированное нулем) присваивается c, а затем d и c инкрементируются. Затем значение c, которое теперь равно 1, присваивается b и b инкрементируется. Наконец, инкрементированное значение b присваивается a. В этом случае окончательное значение a равно 2.

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

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

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

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

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

Знаковое целое преобразуется к короткому знаковому целому (short signed int) посредством усечения старших битов.

Знаковое целое преобразуется к длинному знаковому целому (long signed int) путем размножения знака влево. Преобразование знаковых целых к плавающим величинам происходит без потери информации, за исключением потери некоторой точности, когда преобразуются величины long в float. При преобразовании знакового целого к беззнаковому целому (unsigned int), знаковое целое преобразуется к размеру беззнакового целого и результат интерпретируется как беззнаковая величина.

Преобразование знаковых целых типов представлено в Таблица 5-13. В таблице предполагается, что типы char являются знаковыми по умолчанию. Если во время компиляции используется опция, которая изменяет умолчание типа char на безнаковый, то преобразования типов unsigned char даны в Таблица 5-14.

Из

В

Метод

char

short

дополнение знаком

char

long

дополнение знаком

char

unsigned char

сохранение битов; старший бит теряет функцию знакового бита

char

unsigned short

дополнение знаком до short, преобразование short в unsigned short

char

usigned long

дополнение знаком до long; преобразование long в unsigned long

char

float

дополнение знаком до long; преобразование long в float

char

double

дополнение знаком до long; преобразование long в double

short

char

сохранение младшего байта

short

long

размножение знака

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 не может быть представлено точно, то происходит некоторая потеря точности

long

double

представляется как double; если long не может быть представлено точно как double происходит некоторая потеря точности

Таблица 5‑13 Преобразование знаковых целых типов

Замечание: Тип int эквивалентен или short типу или типу long в зависимости от оборудования. Преобразование значений int производится как для short или long, в зависимости от того, что подходит.

Преобразование беззнаковых целых типов.

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

Когда беззнаковое целое преобразуется к знаковому целому того же размера, то состояние битов не меняется. Однако, значение этого представления изменится, если был установлен знаковый бит.

Преобразование беззнаковых целых типов представлено в Таблица 5-14.

Из

В

Метод

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

unigned short

сохранение младшего слова

unsigned long

float

преобразование к long, преобразование long к float

unsigned long

double

преобразование к long, преобразование long к double

Таблица 5‑14 Преобразование беззнаковых целых типов

Замечание: Тип unsigned int эквивалентен или unsigned short, или unsigned long типам в зависимости от оборудования. Преобразование из unsigned int производятся как для unsigned short или unsigned long в зависимости от того, что подходит.

Преобразование плавающих типов.

Величины float преобразуются к double, не меняясь в значении. Величины double, преобразованные к float, представляются точно, если возможно. Если значение слишком велико для float, то точность теряется.

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

Преобразования плавающих типов сведены в Таблица 5-15 Преобразования плавающих типов.

Из

В

Метод

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; если значение double не может быть точно представлено как float, то точность теряется; если значение слишком велико для представления как float, то результат неопределен

Таблица 5‑15 Преобразования плавающих типов

Преобразование адресных типов.

Указатель на величину одного типа может быть преобразован к указателю на величину другого типа. Результат может быть, однако, неопределенным из-за отличия в требованиях к выравниванию и размерам памяти.

В некоторых реализациях имеются специальные ключевые слова near, far, huge, модифицирующие размер указателей в программах. Указатель может быть преобразован к указателю другого размера; путь преобразования зависит от реализации. Например, на процессоре 8086 компилятор должен использовать значение регистра сегмента, чтобы преобразовать 16-разрядный указатель в 32-х разрядный указатель. Смотрите системную документацию для получения информации о преобразовани указателя.

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

  • если указатель имеет тот же самый или меньший размер, чем целый тип, то указатель преобразуется точно так же как беззнаковое целое, за исключением того, что он не может быть преобразован к плавающей величине;

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

Целый тип может быть преобразован к адресному типу. Если целый тип того же самого размера, что и адресный, то производится простое преобразование к виду указателя (беззнакового целого). Если размер целого типа отличен от размера адресного типа, то целый тип вначале преобразуется к размеру указателя, используя методы преобразования данных в Таблица 5-13 и Таблица 5-14. Затем полученное значение представляется как указатель.

Если поддерживаются специальные ключевые слова near, far, huge, то может быть сделано неявное преобразование адресных величин. В частности, компилятор может по умолчанию создавать указатели определенного размера и производить преобразования получаемых адресных величин, если в программе не появится forward обьявление, переопределяющее это умолчание. Смотрите системную документацию для получения информации об адресных преобразованиях.

Преобразования других типов.

Из определения типа enum следует, что величины enum являются величинами типа int. Поэтому преобразования в и из типа enum осуществляется как для int типов. Тип int эквивалентен типам short или long в зависимости от реализации.

Не допустимы преобразования объектов типа структур и совмещений.

Тип void не имеет значения по определению. Поэтому он не может быть преобразован к любому другому типу, но любая величина может быть преобразована к типу void путем присваивания. Тем не менее, величина может быть явно преобразована cast операцией к void, как это рассматривается в разделе 5.7.2.