Пример. Циклическая адресация
Пример. Работа с целыми числами
Пример. Управление памятью
typedef struct tagABC typedef struct tagABC
{ {
int a; long b;
long b; int a;
int c; int c;
} ABC; } ABC;
extern int Xflag; extern int Xflag;
int function(void) int function(void)
{ {
x = Xflag ? Xflag & 0xFFFE : Lflag; int Lflag = Xflag;
return x; x = Lflag ? Lflag & 0xFFFE : lflag;
} /* длинный код */ return x;
} /* короткий код */
Пояснение.
В данном примере мы сравнили два варианта, которые показывают: как правильно управлять памятью. Основной момент заключается в том, что необходимо выравнивать по двойному слову, иначе за один цикл тип long не сможет быть прочитан. Изначально размещается long, а затем два целых числа. Поэтому в первом случае распределение памяти неправильное. Второй пример: мы имеем переменную на внешнем уровне. Но если ее интенсивно использовать – это приведет к очень длинному коду, потому что будет использован метод адресации через регистры. А если сначала определить внутреннюю переменную и присвоить ей внешнее значение, то дальше доступ к внутренней переменной будет происходить через SP(stack pointer). Что занимает гораздо меньше времени и места. Вывод - лучше работать с локальными, а не с глобальными переменными.
long mult(int sw, int a, int b, long* res)
{
long result;
switch(sw)
{
case 0: /* не корректно */
result = a * b; *res = a + b;
break;
case 1: /* не корректно */
result = (long)(a * b); *res = (long)(a + b);
break;
case 2: /* корректно */
result = (long)a * b; *res = (long)a + b;
break;
default: /* корректно */
result = (long)a * (long)b; *res = (long)a + (long)b;
}
return result;
}
Пояснение.
Рассмотрим первую часть программы (case 0, case 1), которая некорректно производит вычисления. Предположим, что необходимо получить результат типа long (32-битный). В данном примере, вследствие перемножения и сложения двух целый чисел, результат преобразуется к 16-битному, возможно с сатурацией (насыщением). А потом только расширяется до длинного. Поэтому такая реализация будет ошибочна, в связи с тем, что происходит потеря диапазона чисел.
Теперь рассмотрим вторую часть программы(case 2, default). В данном случае, мы изначально один из аргументов преобразуем в long, поэтому дальнейшие операции выполняются с длинными операндами. И результат вычисляется без потерь. Это объясняется тем, что компилятор преобразует второй аргумент к типу первого.
Циклическая адресация представляет метод адресации, при котором происходит циклическое обращение к ячейкам некоторой области памяти (к ячейкам буфера), т.е. адресация осуществляется на основе циклического буфера b[x]. Этот буфер представляет собой набор ячеек в памяти данных, где за последней ячейкой буфера как бы находится первая ячейка буфера, а перед первой ячейкой — как бы находится последняя ячейка. Таким образом, не зависимо от значения смещения, исполнительный адрес всегда будет находиться внутри этой области.
long circ(const int *a, const int *b, int n, int m)
{
int i, x=0;
long sum=0;
for(i=0; i<n; i++)
{
sum += (long)a[i] * b[x % m];
x++;
}
return sum;
}
Компилятор не поддерживает аппаратурные механизмы циклической адресации микропроцессора.