Справочник по C/C++
Математические макросы обобщенного типа

В стандарте С99 определены три версии для большинства математических функций: одна - для параметров типа float, другая - для параметров типа double и третья - для параметров типа long double. Например, в стандарте С99 определены следующие функции для операции вычисления синуса.

double sin(double arg);
float sinf(float arg);
long double sinl(long double arg);

Все три функции выполняют одну и ту же операцию, разница лишь в типе принимаемых ими данных. Причем для всех функций версия, работающая с типом double, - это оригинальная функция, определенная в стандарте С89, a float- и long double-версии добавлены в стандарте С99. В именах float-версий используется суффикс f, а в именах long double-версий - суффикс l.(Необходимость в применении различных имен вызвана тем, что язык С не поддерживает перегрузки функций.) Предоставляя три различные функции, стандарт С99 позволяет вызвать ту, которая более точно соответствует конкретным условиям. Как упоминалось выше в данной главе, по тем же причинам каждая из функций математики комплексных чисел также представлена тремя версиями.

Несмотря на очевидную полезность наличия трех версий математических функций и функций комплексных чисел, работать с ними не совсем удобно, Во-первых, при передаче данных определенного типа нужно не забыть приписать к имени функции надлежащий суффикс. Это и утомительно, и повышает вероятность возникновения ошибок. Во-вторых, если в процессе разработки проекта изменить тип данных, передаваемых одной из таких функций, нужно не забыть изменить и суффикс в имени функции. А это, опять-таки, очень способствует "размножению" ошибок и действует угнетающе на самого программиста. Чтобы справиться с этими(и другими) проблемами, в стандарте С99 определен набор макросов обобщенного типа, которые можно использовать вместо математических или комплексных функций. Эти макросы автоматически выполняют преобразование в соответствующую функцию в зависимости от типа аргумента. Макросы обобщенного типа определены в заголовке <tgmath.h>, который автоматически включает заголовки <math.h> и <complex.h>.

Для макросов обобщенного типа используются те же имена, что и для double-версий математических или комплексных функций, в которые они преобразуются.(Эти имена также совпадают с именами функций, определенными в стандарте С89 и языке C++.) Следовательно, макрос обобщенного типа для функций sin(), sinf() и sinl() использует имя sin(). Макрос обобщенного типа для функций csin(), csinf() и csinl() также использует имя sin(). Как уже упоминалось, соответствующая функция вызывается в зависимости от типа аргумента. Например, в программе определены следующие переменные.

long double Idbl;
float complex fcmplx;

Тогда вызов

cos(Idbl)

преобразуется в вызов

cosl(Idbl),

а вызов

cos(fcmplx)

преобразуется в вызов

ccosf(fcmplx).

Как проиллюстрировано в приведенных выше примерах, использование макросов обобщенного типа предоставляет программисту на С удобство без потери производительности, точности или совместимости(переносимости) программного кода.

ПРИМЕЧАНИЕ. Если вы программируете на языке C++, в использовании макросов обобщенного типа нет никакой необходимости, поскольку язык C++ предоставляет перегруженные версии математических и комплексных функций.