Додаток В. Приклад програмування бітових операцій і операцій зсуву#

Програма упакування#

Слово стану пристрою в системі уведення-виведення подається у вигляді:

№ розрядів

15

14

13

12

11

10

09

08

07

06

05

04

03

02

01

00

Значення

C

C

C

C

C

0

F

B

N

N

N

N

N

N

N

N

де

  • C..C — код стану;

  • F — ознака помилки (1 або 0);

  • B — ознака зайнятості (1 або 0);

  • N..N — кількість байтів, переданих в останню операцію.

Розроблення алгоритму розв’язання#

  1. Уведення значень складових частин слова стану пристрою. Для кожної частини потрібно вивести запрошення на уведення та увести дані.

  2. Занесення в слово стану пристрою коду стану. У змінній, яка зберігає значення коду стану, потрібно виділити 5 молодших розрядів, виконавши операцію побітового логічного І між значенням змінної та двійковою константою 00011111 (шістнадцятковою константою 0x1F). Одержане значення потрібно зсунути на 11 розрядів уліво.

  3. Занесення в слово стану пристрою ознаки помилки. У змінній — ознаці помилки — потрібно виділити один молодший розряд, виконавши операцію побітового логічного І з константою 1. Одержане значення потрібно зсунути на 9 розрядів уліво. Щоб додати одержаний код до коду, одержаного на попередньому кроці, потрібно виконати операцію побітового логічного АБО між попереднім значенням слова стану пристрою та одержаним кодом.

  4. Занесення в слово стану пристрою ознаки зайнятості. У змінній — ознаці зайнятості — потрібно виділити один молодший розряд у спосіб, описаний вище. Одержане значення потрібно зсунути на 8 розрядів уліво та додати до коду, одержаного на попередньому кроці, у спосіб, описаний вище.

  5. Занесення в слово стану пристрою кількості байтів. У змінній — кількості байтів — потрібно виділити 8 молодших розрядів виконавши операцію побітового логічного І з константою 0xFF. Одержане значення потрібно додати до коду, одержаного на попередньому кроці.

Якщо значення складових частин коду, уведені оператором, не виходять за діапазон допустимих для них значень, операція виділення молодших байтів зайва. Але її потрібно передбачити на випадок помилок оператора.

Визначення змінних програми#

Для роботи програми потрібні змінні для збереження складових частин коду. Для кожної складової частини достатньо 1 байту, тому тип цих змінних може бути char або unsigned char. Діапазони можливих значень цих змінних такі:

  • c (код стану) — від 0 до 31;

  • f (ознака помилки) — від 0 до 1;

  • b (ознака зайнятості) — від 0 до 1;

  • n (кількість байтів) — від 0 до 255.

У змінних с, f, b старший розряд байта не використовується, тому немає значення, якого типу вони будуть, char або unsigned char. У змінній n старший розряд використовується, тому вона обов’язково повинна бути типу unsigned char.

Окремо потрібна змінна для збереження результуючого коду слова стану пристрою — двобайтова змінна, у якій старший розряд використовують як кодовий, а не як знаковий. Тому ця змінна повинна бути типу unsigned int.

Розроблення тексту програми#

Текст програми починається з підключення в програму файлу stdio.h: #include <stdio.h>. У ньому містяться описи стандартних функцій уведення-виведення, які неодмінно використовуватимуться в програмі. Далі йдуть заголовок функції main():

int main(void)

та оголошення змінних:

char c;
char f;
char b;
unsigned char n;
unsigned int UnitStateWord;

Уведення коду стану складається з виводу на екран запрошення:

printf("Уведіть код стану (0-31): ");

та, власне, уведення значення в змінну с:

scanf("%hhd", &c);

Аналогічні пари операторів повторюються для уведення значень f, b, n. Усі значення уводять як десяткові числа, використовуючи %hhd в специфікаціях формату. hh тут означає розмір цілого числа (1 байт).

Далі йде формування упакованого коду, яке точно повторює описані кроки алгоритму:

UnitStateWord = ((unsigned char) c & 0x1F) << 11;

Перетворення типу змінної c в unsigned char потрібне, інакше зсув 8-розрядного коду на 11 розрядів призведе до втрати потрібних кодів.

Далі продовжується формування коду:

UnitStateWord |= ((unsigned char) f & 1) << 9;
UnitStateWord |= ((unsigned char) b & 1) << 8;
UnitStateWord |= n & 0xFF;

Виведення результату виконує оператор

printf("\nСлово стану пристрою = %04x\n", UnitStateWord);

Результат виводять як шістнадцяткове число з 4 цифр (що відповідає 2 байтам), обов’язково виводячи провідні нулі.

Повний текст програми наведено нижче.

Запустити цей код можна за [посиланням](https://repl.it/@GasperPaul/AppendixC-Example-C1).
#include <stdio.h>

int main(void)
{
    char c; /*код стану*/
    char f; /*ознака помилки*/
    char b; /*ознака зайнятості*/
    unsigned char n; /*кількість байтів*/
    unsigned int UnitStateWord; /*слово стану*/

    /*уведення складових частин*/
    printf("Уведіть код стану (0-31): ");
    scanf("%hhd", &c);
    printf("Уведіть ознаку помилки (0/1): ");
    scanf("%hhd", &f);
    printf("Уведіть ознаку зайнятості (0/1): ");
    scanf("%hhd", &b);
    printf("Уведіть кількість переданих байтів (0-255): ");
    scanf("%hhd", &n);
  
    /*формування упакованого коду*/
    UnitStateWord  = ((unsigned char) c & 0x1F) << 11;
    UnitStateWord |= ((unsigned char) f & 1) << 9;
    UnitStateWord |= ((unsigned char) b & 1) << 8;
    UnitStateWord |= n & 0xFF;
  
    /*виведення результату*/
    printf("\nСлово стану пристрою = %04x\n", UnitStateWord);
    return 0;
}

Відлагодження програми#

Відлагодження програми можна вести в покроковому режимі з відстеженням значень змінних — складових частин — під час їх уведення, а також коду-результату — на кроках його формування. Для останнього може виникнути незручність, тому що в режимі налагодження значення змінної UnitStateWord буде подано як десяткове число, хоча для завдання зручніше бачити його як шістнадцяткове або двійкове. Для такого відстеження зручніше вставити у відповідні місця тексту програми виклики функції printf, які виводитимуть проміжні значення коду в шістнадцятковому форматі.

Результати роботи програми#

За результатами роботи програми на екран буде виведено результати, схожі на наведені нижче:

Уведіть код стану (0-31): 27
Уведіть ознаку помилки (0/1): 1
Уведіть ознаку зайнятості (0/1): 1
Уведіть кількість переданих байтів (0-255): 74

Слово стану пристрою = db4a

Програма розпакування#

Розроблення алгоритму розв’язання#

Алгоритм програми лінійний і складається з таких кроків:

  1. Уведення значення слова стану пристрою.

  2. Виділення зі слова стану пристрою коду стану. Код слова стану пристрою потрібно зсунути на 11 розрядів управо й виділити 5 молодших розрядів, виконавши операцію побітового логічного І з константою 0x1F. Слово стану пристрою залишається незмінним, а одержане значення записується в змінну для коду стану.

  3. Виділення зі слова стану пристрою ознаки помилки. Код слова стану пристрою потрібно зсунути на 9 розрядів управо й виділити 1 молодший розряд, виконавши операцію побітового логічного І з константою 1. Слово стану пристрою залишається незмінним, а одержане значення записується в змінну для ознаки помилки.

  4. Виділення зі слова стану пристрою ознаки зайнятості. Код слова стану пристрою потрібно зсунути на 9 розрядів управо й виділити 1 молодший розряд у спосіб, описаний вище. Слово стану пристрою залишається незмінним, а одержане значення записується в змінну для ознаки зайнятості.

  5. Виділення зі слова стану пристрою кількості байтів. У коді слова стану пристрою потрібно виділити 8 молодших розрядів, виконавши операцію побітового логічного І з константою 0xFF. Одержане значення записується в змінну для кількості байтів.

Визначення змінних програми#

Для роботи програми потрібні такі самі змінні, як і в попередній задачі.

Розроблення тексту програми#

Початок програми складається з заголовку й визначення змінних. Далі йде формування упакованого коду, яке точно повторює кроки вищенаведеного алгоритму:

c = (UnitStateWord >> 11) & 0x1F;
f = (UnitStateWord >>  9) & 1;
b = (UnitStateWord >>  8) & 1;
n = UnitStateWord & 0xFF;

Далі йде виведення коду стану за допомогою оператора

printf("Код стану = %d\n", c);

Подібними операторами виконується й виведення інших результатів.

Повний текст програми наведено нижче.

#include <stdio.h>

int main(void)
{
    char c; /*код стану*/
    char f; /*ознака помилки*/
    char b; /*ознака зайнятості*/
    unsigned char n; /*кількість байтів*/
    unsigned int UnitStateWord; /*слово стану*/

    /*уведення слова стану пристрою*/
    printf("Уведіть cлово стану пристрою\n");
    printf("(16-кове число від 0 до 0xFFFF): ");
    scanf("%x", &UnitStateWord);

    /*виділення складових частин*/
    c = (UnitStateWord >> 11) & 0x1F;
    f = (UnitStateWord >>  9) & 1;
    b = (UnitStateWord >>  8) & 1;
    n = UnitStateWord & 0xFF;

    /*виведення результатів*/
    putchar('\n');
    printf("Код стану = %d\n", c);
    printf("Ознака помилки = %d\n", f);
    printf("Ознака зайнятості= %d\n", b);
    printf("Кількість переданих байтів = %d\n", n);
    return 0;
}

Результати роботи програми#

За результатами роботи програми на екран буде виведено результати, схожі на наведені нижче:

(16-кове число від 0 до 0xFFFF): cb42

Код стану = 25
Ознака помилки = 1
Ознака зайнятості = 1
Кількість переданих байтів = 66