Операции сдвига
Адресная арифметика
Аддитивные операции, выполняемые над указателем и целым, имеют осмысленный результат в том случае, если указатель адресует массив памяти, а целое значение представляет смещение в пределах этого массива. Преобразование целого значения к адресному смещению предполагает, что в пределах смещения вплотную расположены элементы одинакового размера. Это предположение справедливо именно для элементов массива, поскольку массив определяется как последовательность значений одинакового типа, расположенных в смежных ячейках памяти. Способ хранения других типов данных не гарантирует сплошного заполнения памяти, т.е. даже между ячейками памяти, содержащими элементы одного и того же типа данных, возможны участки неиспользованной памяти. Поэтому корректность сложения и вычитания адресов, ссылающихся на какие-либо другие объекты, не гарантируется.
На компьютерах с сегментной архитектурой памяти (в частности, с микропроцессором типа 8086/8088) аддитивные операции над адресным и целым значениями могут не всегда выполняться правильно. Это вызвано тем, что указатели, используемые в программе, могут иметь различные размеры в зависимости от используемой модели памяти. Например, при компиляции программы в некоторой стандартной модели памяти адресные модификаторы (near, huge, far) могут специфицировать для какого-либо указателя другой размер, чем определяемый по умолчанию выбранной моделью памяти. Более подробная информация о работе с указателями в различных моделях памяти приведена в разделе 8 "Модели памяти".
Примеры:
int i = 4, j;
float x[10];
float *px;
px = &x[4] + 1; /* пример 1 */
j = &x[i] — &x[i-2]; /* пример 2*/
В первом примере целочисленный операнд i складывается с адресом пятого (по порядку следования) элемента массива х. Значение i умножается на длину типа float и складывается с адресом x[4]. Значение результирующего указателя представляет собой адрес девятого элемента массива.
Во втором примере адрес третьего элемента массива х (заданный как &х[i-2]) вычитается из адреса пятого элемента (заданного как &x[i]). Полученная разность делится на размер типа float. В результате получается целое значение 2.
Операции сдвига сдвигают свой первый операнд влево (<<) или вправо (>>) на число разрядов машинного слова, специфицированное вторым операндом. Оба операнда должны быть целыми значениями. Выполняются преобразования по умолчанию, причем в СП MSC над обоими операндами совместно, а в СП ТС независимо над каждым операндом. Например, если переменная b имеет тип int, а переменная и тип unsigned long, то перед выполнением операции b<<u в СП MSC переменная b будет преобразована к типу unsigned long.
Тип результата в СП ТС — это тип левого операнда после преобразования, а в СП MSC — единый тип преобразованных операндов. В некоторых ситуациях результат в СП ТС и в СП MSC может оказаться различным.
При сдвиге влево правые освобождающиеся биты заполняются нулями. При сдвиге вправо метод заполнения освобождающихся левых битов зависит от того, какой тип результата получен после преобразования первого операнда. Если тип unsigned, то свободные левые биты заполняются нулями. В противном случае они заполняются копией знакового бита.
Если второй операнд отрицателен, то результат операции сдвига не определен.
При выполнении операций сдвига ситуация потери значимости не контролируется. Если результат сдвига не может быть представлен типом первого операнда после преобразования, то информация теряется.
Пример:
unsigned int х, у, z;
х= 0х00АА;
у = 0х5500;
z= (х<<8) + (у>>8);
В примере х сдвигается влево на 8 позиций, а у сдвигается вправо на 8 позиций. Результаты сдвигов складываются, давая значение ОхАА5а, которое присваивается z.