Опубликован: 14.12.2010 | Уровень: для всех | Доступ: платный
Лекция 17:

Операции с разрядами (битами) в языке С

< Лекция 16 || Лекция 17: 1234 || Лекция 18 >

Задание 6

  1. Дополните программу выводом на консоль прочитанного числа из текстового файла.
  2. В качестве вводимых данных используйте год и месяц рождения пользователя (студента).
  3. Выполните ротацию шестнадцатеричных чисел, записанных в текстовый файл с именем compX.txt, где Х – номер компьютера, за которым выполняется лабораторная работа. В качестве тестовых чисел и числа битов ротации примите: (0xABCDEF00u, 8), (0xABCDEF00u, –16), (0xFFFF1122u, 4), (0xFFFF1122u, –2), (0xABCDEF00u, 0), (0xABCDEF00u, 44).
  4. Напишите программу по ротации восьмеричных чисел.

Пример 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.

Значения битов остатков от деления двух чисел

Рис. 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

  1. В качестве вводимых чисел примите 2*Х, где Х – номер компьютера, за которым выполняется лабораторная работа.
  2. Выведите на консоль размерность в байтах объединений и структур, определенных в программе.
  3. Проанализируйте результат выполнения программы при изменении размера битовых полей в структуре функции code16().
  4. Видоизмените программу для ввода трех чисел и определения значений разрядных (битовых) полей после занесения в них остатков от деления на целое число 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.

Пример вывода двоичных кодов заданных символов

Рис. 16.8. Пример вывода двоичных кодов заданных символов

Задание 8

  1. Вместо цикла do–while примените другой оператор цикла.
  2. Напишите программу вывода всех строчных букв латинского алфавита и их двоичных эквивалентов в кодировке 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.

Поразрядный сдвиг влево заданного числа

Рис. 16.9. Поразрядный сдвиг влево заданного числа

Задание 9

  1. Проверьте результат выполнения программы с помощью инженерного калькулятора (calc).
  2. В программу добавьте нумерацию результатов вывода десятичного числа и его двоичного эквивалента.
  3. Введите число своего дня рождения пользователя.
  4. Проверьте программу при вводе отрицательных целых чисел.
  5. Измените программу для поразрядного сдвига вправо.

Контрольные вопросы

  1. Как осуществляется нумерация разрядов байта?
  2. Для каких систем счисления в языке С имеются классификаторы форматируемых данных?
  3. Какие логические поразрядные операции существуют в языке С?
  4. Какие логические операции сдвига существуют в языке С? Какими операторами они реализуются?
  5. Что такое битовое поле в языке С? Где оно может быть определено?
  6. В чем отличие поразрядных и логических операторов НЕ, И и ИЛИ?
  7. Как можно обменять значения двух целочисленных переменных без использования третьей переменной?
  8. Чем отличается операция сдвига вправо для типов int и unsigned?
< Лекция 16 || Лекция 17: 1234 || Лекция 18 >
Мухаммадюсуф Курбонов
Мухаммадюсуф Курбонов
Александр Соболев
Александр Соболев
Россия
Артем Полутин
Артем Полутин
Россия, Саранск