Шаг 42.
Microsoft Visual C++ 2010. Язык С/С++.
Операции и выражения присваивания

    На этом шаге мы рассмотрим указанные конструкции.

    Выражения вида i=i+2; можно записывать в виде i+=2; (читается: к i добавить 2). Это правило распространяется на операции: +, -, *, /, %, <<, >>, &, |, ~.

    Ниже приведен текст программы, которая подсчитывает число ненулевых битов целого числа и использует операцию сдвига.

// Oper.cpp: главный файл проекта.

#include "stdafx.h"
#include <stdio.h> //for getchar(), putchar()
#include <conio.h>

#include <clocale> //обязательно для функции setlocale()

using namespace System;

//--- Проверка побитовых логических операций ------------
//--- Функция подсчета количества битов в целом числе ---
int bitcount(unsigned int n)
{
	int b;
	for(b=0; n != 0; n>>=1) 
		if(n & 01)    //01 - восьмеричная единица
			b++;
	return b;
}


int main()
{
	setlocale(LC_ALL,"Russian"); //функция setlocale() с аргументами
	                             //для корректного вывода кириллицы

	int n=017; //восьмеричное число (4 единицы)
	printf("Количество единиц в числе n=%d\n",bitcount(n));

	_getch();
        return 0;
}
Архив проекта можно взять здесь.

    Суть алгоритма функции bitcount() состоит в следующем: в цикле, который идет по переменной b, целое число n сравнивается с восьмеричной единицей (она же - двоичная единица) с помощью операции "&" (и). Так как число 01 можно представить и как, например, 00000001, то, учитывая, как работает операция "&" , можно сказать, что результатом вычисления выражения (n & 01) будет значение последнего бита числа n.

    Действительно:

    Следовательно, выражение (n & 01) "просматривает" все биты числа n. То есть в теле оператора, содержащего это выражение, можно подсчитать, сколько раз выражение (n & 01) было равно единице (что на самом деле означает, сколько единиц содержит число n). Просмотр содержимого числа n происходит за счет сдвига его содержимого вправо на один бит в каждом цикле.

    Мы видели, что выражение n>>=1 равносильно выражению n=n>>1 (т. е. "сдвинуть содержимое переменной n на один разряд вправо и результат записать в n"). Поэтому действие будет происходить так: сначала в заголовочной части цикла for вычислится значение переменной цикла b, которая получит значение ноль. Затем там же, в заголовочной части for, вычислится выражение, определяющее условие продолжения/завершения цикла (n != 0). Следовательно, значение переменной, в которой мы накапливаем единицы, должно быть ненулевым.

    Нулевым оно может стать потому, что после каждого цикла до перехода на новый цикл мы сдвигаем вправо на один разряд содержимое n, что, в конце концов, приведет к тому, что в значении n останутся только нули.

    Но здесь надо иметь в виду следующее: число, которое хранится в переменной типа int, может иметь знак. Точнее знак есть всегда, но он может быть отрицательным. При сдвиге вправо освобождающиеся биты будут заполняться содержимым знакового разряда. Если число положительное, то ничего страшного в этом нет - его знаковый разряд содержит ноль и освобождающиеся при сдвиге вправо биты будут заполнены нулями. Это так называемый арифметический сдвиг числа.

    Если же число отрицательное, то в его знаковом разряде будет единица, и ею станут заполняться освобождающиеся при сдвиге биты. Вот этого-то нам как и не надо! Чтобы избежать такой неприятности, следует сдвигаемое вправо число объявить как unsigned (беззнаковое; у нас так и объявлена переменная n). В этом случае освобождающиеся от сдвига вправо разряды станут заполняться не знаковым разрядом, а нулем. Такой сдвиг называют логическим.

    Результат работы приложения приведен на рисунке 1.


Рис.1. Результат работы приложения

    На следующем шаге мы рассмотрим условное выражение.




Предыдущий шаг Содержание Следующий шаг