Препроцессор языка С
Макрос подтверждения 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.
Результат Version C: 1 означает, что компилятор поддерживает стандарт ANSI С.
- Сделайте так, чтобы признак простого или непростого числа передавался из макроса. Этот признак должен использоваться в функции main(), для вывода соответствующего сообщения на консоль.
- В программе предусмотрите вывод на консоль общего количества строк программного кода.
- В программе предусмотрите вывод на консоль даты компиляции и имени компилируемого файла.
- Напишите макрос с формальными параметрами для проверки на четность целого числа, введенного с клавиатуры.
- Напишите макрос с формальными параметрами для обмена значениями двух переменных (типа функции swap() ).
- Напишите макрос с формальными параметрами по вычислению площади круга по известному радиусу (вводимого с клавиатуры). Значение числа _ определить с 15 знаками после десятичной точки при использовании директивы #define.
- Введите в программу вычисление случайных чисел, равномерно распределенных в интервале [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.
Задание 2
- Стихотворение запишите в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.
- Вместо препроцессорной директивы #ifdef примените другую директиву условной компиляции.
- В программу включите директиву #else.
- Какой препроцессорной директивой можно исключить из программы именованную константу AZA?
- Создайте файл dog.h с содержимым файла dog.txt и подключите его к проекту вместо файла dog.txt.
- Напишите "чистую" рекурсивную функцию для распечатки стихотворения о попе и его собаке. В качестве аргумента функции включите количество стихотворных строф. Подсчитайте количество рекурсивных вызовов.
Пример 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.
Пример выполнения программы показан на рис. 19.4.
Задание 3
- Внесите изменения в программу, чтобы условие о невозможности компиляции было реализовано без директивы #error.
- Вместо специализированной константы _DEBUG введите собственную символическую константу COMP_X, где Х – номер компьютера, на котором выполняется лабораторная работа.
- Напишите программу со стеком, в который будут помещаться вводимые слова, а после предусмотреть возможность извлечения набранных слов (по дисциплине LIFO).



