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

Препроцессор языка С

< Лекция 19 || Лекция 20: 123 || Лекция 21 >

Пример 4. С помощью директивы #define и оператора препроцессора # напишите программу определения кода вводимого символа.

Программный код решения примера:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <conio.h>
#include <locale.h>

#define CHAR_COD(c)  ""#c""

int main (void) {
	char ch;
	setlocale (LC_ALL, "rus");

	printf("\n Введите символ: ");
	scanf("%c", &ch);
  printf("\n %s \"%c\", его код %d", CHAR_COD(Символ), ch, ch);

	printf("\n\n ... Нажмите любую клавишу: ");
	_getch();
	return 0;
}

Оператор # должен использоваться в макросах с аргументами, поскольку операнд после ссылается на аргумент макроса [19.5]. В данном случае строка "Символ" подставляется в заменяющий текст вместо #c.

Пример выполнения программы показан на рис. 19.5.

Пример определения кода вводимого символа

Рис. 19.5. Пример определения кода вводимого символа

Задание 4

  1. Напишите программу повторного ввода символов с клавиатуры до тех пор, пока не будет введен символ "z".
  2. Выполните макроподстановку со строкой "compX" и присоединяемой строкой "Х" с помощью функции printf(), где Х – номер компьютера, на котором выполняется лабораторная работа.

Пример 5. С помощью директивы #define и оператора препроцессора ## классифицируйте четность или нечетность кода вводимого символа.

Программный код решения примера:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <conio.h>
#include <locale.h>
// LEXEME - лексема
#define TWO_LEXEME(a,b)  a ## b

#define CHAR_COD(c)  ""#c""

int main (void)
 {
	char ch;
	setlocale (LC_ALL, "rus");
	printf("\n Введите символ: ");
	scanf("%c", &ch);

	if (!(ch % 2))
printf("\n %s \"%c\", его код %d %s", \
CHAR_COD(Символ), ch, ch, TWO_LEXEME(" - четный","!"));
	
     else
printf("\n %s \"%c\", его код %d %s", \
CHAR_COD(Символ), ch, ch, TWO_LEXEME(" - не ", "четный."));

	printf("\n\n ... Нажмите любую клавишу: ");
	_getch();
	return 0; }

Данная программа – некоторое расширение предыдущей программы. Операция конкатенации строк ## осуществляется с помощью макроса TWO_LEXEME() с двумя аргументами.

Пример выполнения программы показан на рис. 19.6.

Пример классификации четности символа

Рис. 19.6. Пример классификации четности символа

Задание 5

  1. В программе примените только буквы латинского алфавита.
  2. Для записи четности или нечетности введенного символа предусмотрите массив символов str1 и str2.
  3. Произведите конкатенацию двух строк "comp" и "Х" с помощью операции ##, где Х – номер компьютера, на котором выполняется лабораторная работа.

Пример 6. Напишите программу формирования структуры с информацией о студенте (об учащемся) и с помощью директивы #pragma осуществить оптимизацию использования памяти, выделяемой под структуру.

Для решения примера используем справку системы Visual Studio 2010 (для этого из меню Help \to Index \to Look for: вписать pragma, затем в правой части панели обратиться к опции pack). Опция pack определяет, как компилятор выравнивает данные при сохранении в памяти.

Программный код решения примера:

#include <stdio.h>
#include <conio.h>

#pragma pack (show)
 
struct Student
{
	char name[21];   // имя, фамилия
	int age;         // возраст, полных лет
	char gender;     // пол, мужской, женский
	double mean;     // средний балл успеваемости
} st1;


#pragma pack (push)
#pragma pack (1) 
#pragma pack (show)


struct Student_pack
{
	char name[21];   // имя, фамилия
	int age;         // возраст, полных лет
	char gender;     // пол, мужской, женский
	double mean;     // средний балл успеваемости
} st2;

#pragma pack (pop)
#pragma pack (show)

int main (void)
{
	puts("");
	printf (" sizeof (struct st1) = %d\n", sizeof (st1));
	printf (" sizeof (struct st2) = %d\n", sizeof (st2));

		printf("\n ... Press any key: ");
	_getch();

	return 0;
}

В программе опция pack(show) используется для диагностики текущей упаковки полей структуры. Опция pack(1) используется для выравнивания областей памяти полей структуры, кратных единице. Опция pack(push) используется для "вталкивания" параметров. Опция pack(pop) используется для "выталкивания" параметров.

После компиляции программы можно видеть сообщения, показанные на рис. 19.7.

Сообщения об упаковке полей структуры

Рис. 19.7. Сообщения об упаковке полей структуры

Предупреждения (warning) уведомляют о размере упаковки. Сначала область памяти выделяется под размер в байтах, кратных 8, затем, кратных 1. После выталкивания параметров снова область памяти становится кратной 8 – наибольшему типу данных double элемента mean структуры.

Результат выполнения программы показан на рис. 19.8.

Пример определения месяца года

Рис. 19.8. Пример определения месяца года

Как видно, размер первой структуры равно 40 байтов (кратных 8). Размер второй структуры, для которой произведена упаковка, равен 34, что соответствует сумме размеров полей структуры, т. е. 34 = 21 + 4 + 1 + 8.

Примечание. Выравнивание полей структуры можно выполнить при настройке компилятора в MS Visual Studio 2010. Эта настройка показана на рис. 19.9.


Рис. 19.9.

Задание 6

  1. Запишите в двоичные файлы созданные структуры, проведя их инициализацию. Определите и сравните размеры созданных бинарных файлов. Произведите также чтение данных из бинарных файлов с выводом результата на консоль.
  2. В программе для аргумента pack() примите 1, 2, 4, 8, 16. Объясните результаты выполнения программы.
  3. Размер массива типа char примите равным 31, т. е. char name[31]. Объясните результат выполнения программы.
  4. В качестве элементов структуры используйте следующие типы данных: float, short int. Объясните результат выполнения программы.
  5. Используя меню Project \to Properties (Alt \to F7), произведите установку параметров закладки Struct Alignment для всех возможных значений (1 Byte, 2 Bytes, 4 Bytes, 8 Bytes, 16 Bytes). Определите также значение выравнивания полей структуры по умолчанию (Default).

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

  1. Какое назначение отводится препроцессору языка С?
  2. Что такое условная компиляция, производимая препроцессором? В каких целях производится условная компиляция?
  3. Назовите операторы препроцессора. Для чего они используются?
  4. Какие директивы препроцессора используются наиболее часто в программах, написанных на языке С?
  5. Что такое макроопределение препроцессора? Как оно реализуется?
< Лекция 19 || Лекция 20: 123 || Лекция 21 >
Мухаммадюсуф Курбонов
Мухаммадюсуф Курбонов
Александр Соболев
Александр Соболев
Россия
Артем Полутин
Артем Полутин
Россия, Саранск