11 класс, 2017-2018 учебный год

Путеводитель по прошедшим урокам

Занятие 28-го ноября

Дорассказывал, кому не успел, про битовые поля и операции, да про структуры. Код, относящийся к этим вопросам, разбиравшийся на уроке:

#define F_CP866		0x01
#define F_CP1251	0x02
#define F_KOI8R		0x04
#define T_CP866		0x08
#define T_CP1251	0x10
#define T_KOI8R		0x20

...

int main(char *argv[], int argc)
{
	int mode = 0;

	...

	if (!strncmp(argv[1], "cp866"))
		mode = mode | F_CP866;
	else if (!strncmp(argv[1], "cp1251"))
		mode |= F_CP1251;
	else if (!strncmp(argv[1], "koi8-r"))
		mode |= F_KOI8R;
	else {
		fprintf(stderr, "Bad source encoding '%s'.\n", argv[1]);
		exit(1);
	}

	...

	if (mode & F_KOI8R) {
		<... обрабатываем случай раскодирования из KOI8-R ...>
	}
}
Одной из групп рассказал про data-driven, было два-с-половиной примера. Первый, похуже:
struct from_args {
	char *name;		/* Encoding name */
	unsigned char mask;	/* Bit mask, OR-flavor */
};

...

int main(char *argv[], int argc)
{
	struct from_args from_a[] = {
	    {"cp866", F_CP866},
	    {"cp1251", F_CP1251},
	    {"koi8-r", F_KOI8R}
	};
	unsigned char mode = 0;
	int i, matched;

	...

	for (i = 0, matched = 0; i < sizeof(from_a)/sizeof(from_a[0]); i++) {
		if (!strncmp(argv[1], from_a[i].name)) {
			mode |= from_a[i].mask;
			matched = 1;
			break;
		}
	}
	if (!matched) {
		fprintf(stderr, "Bad source encoding '%s'.\n", argv[1]);
		exit(1);
	}
}
«Половинка», избавляющая от matched (break — крайне важен!):
#define COUNTOF(a) (sizeof(a)/sizeof((a)[0]))
	for (i = 0; i < COUNTOF(from_a); i++) {
		if (!strncmp(argv[1], from_a[i].name)) {
			mode |= from_a[i].mask;
			break;
		}
	}
	if (i == COUNTOF(from_a) {
		fprintf(stderr, "Bad source encoding '%s'.\n", argv[1]);
		exit(1);
	}
#undef COUNTOF

Второй, намного лучше:

struct from_args {
	char *name;		/* Encoding name */
	unsigned char mask;	/* Bit mask, OR-flavor */
};

...

int main(char *argv[], int argc)
{
	struct from_args from_a[] = {
	    {"cp866", F_CP866},
	    {"cp1251", F_CP1251},
	    {"koi8-r", F_KOI8R},
	    {NULL, 0}
	};
	struct from_args *pfa = &from_a[0];
	unsigned char mode = 0;

	...

	while (pfa->name) {
		if (!strncmp(argv[1], pfa->name)) {
			mode |= pfa->mask;
			break;
		}
		pfa++;
	}
	if (!pfa->name) {
		fprintf(stderr, "Bad source encoding '%s'.\n", argv[1]);
		exit(1);
	}

	...
}

Занятие 24-го ноября

Рассказывал про манипуляцию битами внутри целых типов, экономию целого байта (берегущего мегабайт, естественно), битовые поля, маски и операции.

Разбирали программу, которая принимает как минимум два аргумента-переключателя режимов (в двух группах — перекодировщик, в одной — заполнялка массивов с режимом транспозиции массива):

./prog {cp866|cp1251|koi8-r} {cp866|cp1251|koi8-r} filename

В паре групп успел рассказать про структуры: записную книжку, ее реализацию с помощью четырех «прошитых» общим индексом массивов:

	char *names[];
	char *addrs[];
	char *phones[];
	int ages[];

	names[0] = "Volodia Ulianov";
	addrs[0] = "Red square";
	phones[0] = "None"
	ages[0] = 147;
(«четыре записных книжки для имен, адресов, телефонов и возрастов»).

Ну и про избавление от такой напасти посредством введения-таки структур:

struct pb_entry {
	char *name;
	char *addr;
	char *phone;
	int age;
};

...

int main(void)
{
	struct pb_entry e, *pe;
	struct pb_entry p_book[100];

	e.name = "Eygene";
	e.addr = "Kurchatov square, 1";
	e.phone = "+7 499 196-77-77";
	e.age = 36;

	p_book[0] = e;

	pe = &e;
	if (CURRENT_YEAR > 2017)
		pe->age += (CURRENT_YEAR - 2017);
	...

	p_book[1] = *pe;

	...
}

«Напоминалка»:

Все три бинарных операции бывают равны тождественному преобразованию, если правильно подобрать биты маски. Для чтения содержимого отдельного бита пригодны, как И, так и ИЛИ (с масками от своих визави, которые при модификации битов применяются), вот только И — поуниверсальнее, ибо ноль — он и без палочки очень хорошими свойствами обладает. Инверсия (унарная) всех битов — «~».