Операции с разрядами (битами) в языке С
Задание 6
- Дополните программу выводом на консоль прочитанного числа из текстового файла.
- В качестве вводимых данных используйте год и месяц рождения пользователя (студента).
- Выполните ротацию шестнадцатеричных чисел, записанных в текстовый файл с именем compX.txt, где Х – номер компьютера, за которым выполняется лабораторная работа. В качестве тестовых чисел и числа битов ротации примите: (0xABCDEF00u, 8), (0xABCDEF00u, –16), (0xFFFF1122u, 4), (0xFFFF1122u, –2), (0xABCDEF00u, 0), (0xABCDEF00u, 44).
- Напишите программу по ротации восьмеричных чисел.
Пример 7. Напишите программу по решению следующего примера. С клавиатуры вводятся два целых числа. Остатки от деления их на 16 заносятся соответственно в 4 младших и 4 старших разряда одного байта. Затем следует напечатать изображение содержимого сформированного байта [16.3].
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
#include <local.h>
setlocale(LC_ALL, ".1251");
int main (void)
{
int m, n;
unsigned char k;
//Прототипы функций
void binar (unsigned char ch);
unsigned char code16 (int a, int b);
printf("\n\t Введите первое беззнаковое число N1: ");
scanf_s("%d", &m);
printf("\t Введите второе беззнаковое число N2: ");
scanf_s("%d", &n);
k = code16(m, n);
printf("\n\t Код двух остатков старших и младших разрядов байта: %u", k);
binar(k);
printf("\n Нажмите любую клавише (Press any key): ");
_getch();
return 0;
}
unsigned char code16 (int a, int b){
//Объединение с вложенной структурой
union
{
unsigned char z;
struct
{
unsigned int x : 4; //Младшие биты
unsigned int y : 4; //Старшие биты
} hh;
} un;
un.hh.x = a % 16;
un.hh.y = b % 16;
return (un.z);
}
void binar (unsigned char ch){
int i;
// Объединение с вложенной структурой
union {
unsigned char ss;
// Структура с битовыми полями
struct {
unsigned int a0:1; unsigned int a1:1;
unsigned int a2:1; unsigned int a3:1;
unsigned int a4:1; unsigned int a5:1;
unsigned int a6:1; unsigned int a7:1;
} byte;
} cod;
cod.ss = ch;
printf("\n\n\t Число разрядов:\n\t");
for (i = 0; i < 8; ++i)
printf("%4d", 7 - i);
printf("\n\t Значения битовых полей:\n\t");
printf("%4d%4d%4d%4d%4d%4d%4d%4d",\
cod.byte.a7, cod.byte.a6, cod.byte.a5, cod.byte.a4,\
cod.byte.a3, cod.byte.a2, cod.byte.a1, cod.byte.a0);
printf("\n\n");
}Возможный результат выполнения программы показан на рис. 16.7.
В программе используются две переменных типа объединения и две структурные переменные. Объединение имеет то свойство, что переменные разных типов занимают одну область памяти, соответствующей наибольший размер в байтах. Поэтому если инициализируются одни переменные (например, un.hh.x = a % 16; un.hh.y = b % 16; ), то переменная другого типа ( unsigned char z; ) будет располагаться в той же области памяти, что и переменные типа unsigned int (x и y). В связи с этим якобы неинициализированная переменная un.z возвращается функцией code16(). Размеры полей задаются программистом с учетом того, чтобы в них помещалось соответствующее число, представленное в двоичной системе. Например, если размерность поля равна 2, то в это поле можно записать десятичное число 3, так как его двоичный эквивалент равен 11. В поле с размерностью 8 можно записать число 140, так как его двоичный эквивалент равен 10001100.
Задание 7
- В качестве вводимых чисел примите 2*Х, где Х – номер компьютера, за которым выполняется лабораторная работа.
- Выведите на консоль размерность в байтах объединений и структур, определенных в программе.
- Проанализируйте результат выполнения программы при изменении размера битовых полей в структуре функции code16().
- Видоизмените программу для ввода трех чисел и определения значений разрядных (битовых) полей после занесения в них остатков от деления на целое число 8.
Пример 8. Используя битовые поля структуры, напишите программу вывода на экран дисплея двоичного кода ASCII символа, вводимого с клавиатуры.
Условие примера является классическим, примеры программ приводятся во многих руководствах и учебниках. Ниже приводится некоторая модификация известных программ.
Отметим про наборы символов ASCII. Символы сохраняются в памяти компьютеров с использованием числовых кодов. Часто используется кодировка ASCII (American Standard Code for Information Interchange – американский стандартный код для обмена информацией). Таблицу символов ASCII можно посмотреть в [16.1].
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
//Шаблон структуры с битовыми полями
struct byte {
int b1 : 1; int b2 : 1;
int b3 : 1; int b4 : 1;
int b5 : 1; int b6 : 1;
int b7 : 1; int b8 : 1;
};
// Определение объединения с вложенной структурой
union bits {
char ch;
struct byte bit;
} un;// un - переменная типа объединения
// Прототип функции
void decode (union bits bt, int ch);
// Главная функция
int main (void) {
printf("\n\t Enter any symbol or Ctrl+Z to quit:\n");
do {
printf("\n\t Enter: ");
un.ch = getchar();
if ( (un.ch) == EOF) break;
decode(un, un.ch);
} while ((un.ch = getchar())!= EOF);
printf("\n Press any key: ");
_getch();
return 0; }
// Функция двоичного представления символов
void decode (union bits bt, int ch) {
printf("\tBinary code of '%c':\n", ch);
if (bt.bit.b8) printf("%2c 1", ' ');
else printf("%2c 0", ' ');
if (bt.bit.b7) printf("%2c 1", ' ');
else printf("%2c 0", ' ');
if (bt.bit.b6) printf("%2c 1", ' ');
else printf("%2c 0", ' ');
if (bt.bit.b5) printf("%2c 1", ' ');
else printf("%2c 0", ' ');
if (bt.bit.b4) printf("%2c 1", ' ');
else printf("%2c 0", ' ');
if (bt.bit.b3) printf("%2c 1", ' ');
else printf("%2c 0", ' ');
if (bt.bit.b2) printf("%2c 1", ' ');
else printf("%2c 0", ' ');
if (bt.bit.b1) printf("%2c 1", ' ');
else printf("%2c 0", ' ');
printf("\n");
}Программа ориентирована на 8 бит одного байта целочисленного значения, которым кодируется символ, вводимый с клавиатуры. В функции decode() использовано форматирование на основе символа "пробел".
Возможный результат выполнения программы показан на рис. 16.8.
Задание 8
- Вместо цикла do–while примените другой оператор цикла.
- Напишите программу вывода всех строчных букв латинского алфавита и их двоичных эквивалентов в кодировке ASCII без ввода их с клавиатуры.
Пример 9. Напишите программу левого поразрядного сдвига для вводимого с клавиатуры целого числа с выводом его двоичного эквивалента и с повторными сдвигами влево.
В программе решения примера следует предусмотреть перевод числа из десятичной системы счисления в двоичную систему счисления. При поразрядном сдвиге влево на освободившееся место (места) двоичного числа записываются нули.
Программный код решения примера:
#include <stdio.h>
#include <conio.h>
// Главная функция
int main (void)
{
long int a;
unsigned int m, n;
//Прототип функции
void dec2(long int var, unsigned int m, unsigned int n);
printf("\n\t Enter an integer: ");
scanf_s("%ld", &a);
_flushall();
printf("\t Enter a value shift: ");
scanf_s("%u", &m);
_flushall();
printf("\t Enter number of repeated shifts: ");
scanf_s("%u", &n);
_flushall();
dec2(a, m, n);
printf("\n\n Press any key: ");
_getch();
return 0; }
// Функция поразрядного сдвига
void dec2(long int var, unsigned int m, unsigned int n) {
unsigned int b, i;
long int mask = 1 << 31;
long int M[128];
for (i = 0; i < n; ++i)
M[i] = var << i*m;
printf("\n\t Decimal and its binary equivalent after the shift:\n");
for (i = 0; i < n; ++i) {
if (i == 0) {
printf("\n Initial number %ld:\n\t", M[0]);
for (b = 1; b <= 32; ++b) {
printf("%c", M[0] & mask ? '1' : '0');
M[0] <<= 1; // or: var = var << 1;
if (b % 8 == 0)
putchar(' '); }
}
else {
printf("\n The following number %ld:\n\t", M[i]);
for (b = 1; b <= 32; ++b) {
printf("%c", M[i] & mask ? '1' : '0');
M[i] <<= 1;
if (b % 8 == 0)
putchar(' '); }
}
printf("\n"); }
}В программе предполагалось, что в наличии 32-разрядный компьютер. Кроме того, вывод двоичного эквивалента сделан побайтно, считая, что в одном байте находится 8 бит.
Возможный результат выполнения программы показан на рис. 16.9.
Задание 9
- Проверьте результат выполнения программы с помощью инженерного калькулятора (calc).
- В программу добавьте нумерацию результатов вывода десятичного числа и его двоичного эквивалента.
- Введите число своего дня рождения пользователя.
- Проверьте программу при вводе отрицательных целых чисел.
- Измените программу для поразрядного сдвига вправо.
Контрольные вопросы
- Как осуществляется нумерация разрядов байта?
- Для каких систем счисления в языке С имеются классификаторы форматируемых данных?
- Какие логические поразрядные операции существуют в языке С?
- Какие логические операции сдвига существуют в языке С? Какими операторами они реализуются?
- Что такое битовое поле в языке С? Где оно может быть определено?
- В чем отличие поразрядных и логических операторов НЕ, И и ИЛИ?
- Как можно обменять значения двух целочисленных переменных без использования третьей переменной?
- Чем отличается операция сдвига вправо для типов int и unsigned?


