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

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

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

Макрос подтверждения assert

Макрос assert, определенный в заголовочном файле assert.h, проверяет значение выражения [19.5]. Если значение выражения равно 0 (ложное значение), то assert распечатывает (например, выводит на консоль) сообщение об ошибке и вызывает функцию abort() (из библиотеки stdlib.h ), завершающую работу программы. Например, в программе переменная х должна принимать значения, не превышающие 10. Для проверки и подтверждения такого условия в программу можно включить следующую строку:

assert( x <= 10 );

Если при выполнении данного макроса переменная х окажется больше 10, то выдается сообщение, содержащее номер строки и имя файла (например, main.c), в котором нарушено условие, а выполнение программы при этом прерывается. Формат выводимого сообщения зависит от конкретной реализации системы программирования [19.3]. С помощью assert можно производить отладку программы во многих ее местах. Когда программа будет отлажена, то действие макроса assert можно устранить с помощью символической константы NDEBUG (not debugging – без отладки). Для этого перед заголовочным файлом assert.h следует вставить строку

#define  NDEBUG

#define NDEBUG

Практическая часть

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

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

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

// Макрос с формальными параметрами
#define SIMPLE(x, d, b) for(d = 2; d < x; d++) \
	if (!(x%d)) b = 0;  \
	if (b)  puts("\n It is the simple number"); \
		else puts("\n It is not the simple number");

int main (void) {
	int b = 1, d = 0, x = 13;

	printf("\n Enter the natural number: ");
	scanf("%d", &x);
	
     // Макрос с действительными параметрами
     SIMPLE(x, d, b);
	printf("\n %5sTime: %s\n Version C: %d \n", "", \
		__TIME__, __STDC__);

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

В первой строке программы включена символическая константа для исключения вывода предупреждения относительно функции scanf() в среде MS Visual Studio 2008. В программе показано применение макроса функции с тремя формальными параметрами и несколькими строками программного кода.

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

Проверка введенного числа на простоту

Рис. 19.1. Проверка введенного числа на простоту

Результат Version C: 1 означает, что компилятор поддерживает стандарт ANSI С.

  1. Сделайте так, чтобы признак простого или непростого числа передавался из макроса. Этот признак должен использоваться в функции main(), для вывода соответствующего сообщения на консоль.
  2. В программе предусмотрите вывод на консоль общего количества строк программного кода.
  3. В программе предусмотрите вывод на консоль даты компиляции и имени компилируемого файла.
  4. Напишите макрос с формальными параметрами для проверки на четность целого числа, введенного с клавиатуры.
  5. Напишите макрос с формальными параметрами для обмена значениями двух переменных (типа функции swap() ).
  6. Напишите макрос с формальными параметрами по вычислению площади круга по известному радиусу (вводимого с клавиатуры). Значение числа _ определить с 15 знаками после десятичной точки при использовании директивы #define.
  7. Введите в программу вычисление случайных чисел, равномерно распределенных в интервале [0; Х], где Х – номер компьютера (1, 2, 3, ...), на котором выполняется лабораторная работа. Количество случайных чисел должно соответствовать числу секунд (не равных нулю), определяемых с помощью символической константы __TIME__.

Пример 2. Выполните проверку подключаемого тестового файла и вывести на консоль содержимого этого файла. Содержимое файла – стихотворный пример бесконечной рекурсии: у попа была собака ....

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

// Файл с главной функцией main()

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

// Подключение текстового файла
#ifndef AZA
#define AZA
#include "dog.txt"
#endif

int main (void)  {
	short i , j, n, in;
	i = j = 0;
// для поддержки русских шрифтов
	setlocale (LC_ALL, "rus");

	printf("\n Введите количество стихотворных строф: ");
	in = scanf("%hd", &n);
    if (in != 1 || n < 1) {
	printf("\n Ошибка ввода данных. Нажмите любую клавишу: ");
		_getch();
		exit(1);
	}

// Условие распечатки текстового файла
#ifdef AZA
	
    puts("");
	for (j = 0; j < n; j++ )
    {
         i = 0;
		while (d[i] != NULL)
         {
			printf(" ");
			puts(d[i]);
			i++;
		}
	}

#endif

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

Содержимое текстового файла dog.txt:

char *d[] = {
"У попа была собака,", \
"Он её любил,", \
"Она съела кусок мяса,", \
"Он её убил...",\
"Вырыл ямку, закопал,", \
"На дощечке написал:\n"
 };

Решение примера выполнено в виде двух файлового проекта. Инициализация переменных в главной функции сделано на случай, если не будет определена директива #define AZA, чтобы не было предупреждений компилятора о неиспользованных переменных i и j.

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

Пример распечатки текстового файла

Рис. 19.2. Пример распечатки текстового файла

Задание 2

  1. Стихотворение запишите в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.
  2. Вместо препроцессорной директивы #ifdef примените другую директиву условной компиляции.
  3. В программу включите директиву #else.
  4. Какой препроцессорной директивой можно исключить из программы именованную константу AZA?
  5. Создайте файл dog.h с содержимым файла dog.txt и подключите его к проекту вместо файла dog.txt.
  6. Напишите "чистую" рекурсивную функцию для распечатки стихотворения о попе и его собаке. В качестве аргумента функции включите количество стихотворных строф. Подсчитайте количество рекурсивных вызовов.

Пример 3. С помощью директив условной компиляции и символической константы _DEBUG напишите программу ввода слов с клавиатуры с проверкой возможности компиляции программного кода.

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

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

int main (void) {
	char str[80];

// Начало проверки компилируемого кода
#ifdef _DEBUG
	printf("\n Start debugging\n");
#endif

	do {
		printf("\n Enter a word or \"z\" to exit: ");
		gets_s(str, 79);

#if _DEBUG
		printf("\n The word is \"%s\"\n", str );

#else 
#error This version is not to the C Run-Time Library. \
Break to debugging.

#endif 

	} while (str[0] != 'z' && str[0] != 'Z');

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

Символическая константа _DEBUG будет определяться (существовать) в режиме Debug, которое находится в списке главного меню интегрированной системы MS Visual Studio 2010.

На рис. 19.3 показан выбор режима отладки Debug.

Выбор режима отладки Debug

Рис. 19.3. Выбор режима отладки Debug

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

Пример выполнения режима отладки программы

Рис. 19.4. Пример выполнения режима отладки программы

Задание 3

  1. Внесите изменения в программу, чтобы условие о невозможности компиляции было реализовано без директивы #error.
  2. Вместо специализированной константы _DEBUG введите собственную символическую константу COMP_X, где Х – номер компьютера, на котором выполняется лабораторная работа.
  3. Напишите программу со стеком, в который будут помещаться вводимые слова, а после предусмотреть возможность извлечения набранных слов (по дисциплине LIFO).
< Лекция 19 || Лекция 20: 123 || Лекция 21 >
Мухаммадюсуф Курбонов
Мухаммадюсуф Курбонов
Александр Соболев
Александр Соболев
Россия
Артем Полутин
Артем Полутин
Россия, Саранск