Препроцессор языка С
Макрос подтверждения 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).