Если компилятор поддерживает арифметику комплексных чисел, то в нем доступен файл complex.h, в котором объявлены комплексные аналоги математических функций. Например, в этом файле объявлены функции csqrtf(), csqrt() и csqrtl(), которые возвращают комплексный квадратный корень типа float complex, double complex и long double complex, соответственно. Когда такая поддержка предоставляется, макрос sqrt() из tgmath.h также может разворачиваться в связанную функцию комплексного квадратного корня.
Если вы хотите, скажем, вызвать функцию sqrt() вместо макроса sqrt() , даже несмотря на то, что файл tgmath.h включен, можете поместить имя функции в круглые скобки:
#include
float х = 44.0; double у;
у = sqrt(x); // вызов макроса, следовательно sqrtf(х)
у= (sqrt) (х); // вызов функции sqrt()
Код работает, поскольку имя функционального макроса должно сопровождаться последующей открывающей круглой скобкой, что обходится путем заключения имени в пару скобок. В противном случае круглые скобки не оказывают воздействия на выражение, находящееся внутри них, кроме изменения порядка следования операций, поэтому помещение в скобки имени функции по-прежнему в результате приводит к ее вызову. На самом деле, из-за странно противоречивых правил, принятых в С относительно указателей на функции, для вызова функции sqrt() можно также использовать (* sqrt)().
698 Глава 16
Средство выражений _Generic, добавленное в стандарт С11, является простым способом реализации макросов tgmath.h, не прибегая к механизмам, которые выходят за рамки стандарта С.
Библиотека утилит общего назначения
Библиотека утилит общего назначения содержит множество функций, включая генератор случайных чисел, функции для поиска и сортировки, функции для преобразования и функции для управления памятью. Вы уже видели работу функций rand(), srand(), malloc() и free() в главе 12. В ANSI С прототипы этих функций находятся в заголовочном файле stdlib.h. В разделе V приложения Б перечислены все функции в этом семействе; далее мы рассмотрим некоторые из них более подробно.
ФУНКЦИИ exit() и atexit()
Функция exit() уже применялась явно в нескольких примерах. Вдобавок функция exit() вызывается автоматически при возвращении из main(). В стандарт ANSI добавлена пара интересных возможностей, которые мы еще не использовали. Самая важная из них — возможность указания определенных функций, которые должны вызываться во время выполнения exit(). Функция atexit() обеспечивает это за счет регистрации функций, предназначенных для вызова при выполнении exit(). Функция atexit() принимает в качестве аргумента указатель на функцию.
В листинге 16.16 показано, как это работает.
Листинг 16.16. Программа byebye.c

Препроцессор и библиотека С 699
Ниже показаны результаты пробного запуска:
Введите целое число:
212
212 является четным.
Завершение работы очередной замечательной программы от SeeSaw Software!
Если программа выполняется в IDE-среде, две последних строки вы можете не увидеть.
Рассмотрим результаты второго пробного запуска:
Введите целое число: что?
Это не целое число!
SeeSaw Software приносит искренние соболезнования в связи с отказом программы.
Завершение работы очередной замечательной программы от SeeSaw Software!
Если программа выполняется в IDE-среде, четыре последних строки вы можете не увидеть.
Давайте посмотрим на две основных области: применение функции atexit() и аргументы exit().
Использование функции atexit()
Все-таки есть функция, которая принимает указатели на функции! Чтобы использовать ее, просто передайте адрес функции, которая должна быть вызвана при выходе. Поскольку имя функции действует как адрес, когда применяется в качестве аргумента функции, для аргумента можно указывать имя sign of f или too bad. Затем atexit() регистрирует эту функцию в списке функций, предназначенных для выполнения при вызове exit(). Стандарт ANSI гарантирует, что список может вмещать не менее 32 функций. Каждая из них добавляется с помощью отдельного вызова atexit(). Когда функция exit(), в конце концов, вызывается, она выполняет эти функции, причем первой выполняется функция, добавленная в список последней.
Обратите внимание, что в результате недопустимого ввода пользователя вызываются обе функции, sign_of f() и too bad(), но в случае ввода допустимого значения вызывается только sign of f(). Дело в том, что оператор if регистрирует функцию too bad() только для случая недопустимого ввода. Кроме того, первой была вызвана функция, зарегистрированная последней.
Читать дальше