Некоторые частичные ответы и ответы на связанные вопросы:
Если предполагаемая функция должна возвращать тип с плавающей запятой, тест прост:
#define HAS_PROTO_FP_RET_1_ARG(f) !!((1?1:(f)(0))/2)
1 получает повышениек типу с плавающей запятой, если и только если объявлено, что f
возвращает тип с плавающей запятой, а деление на 2 приводит к ненулевому значению, если и только если 1 имеет тип с плавающей запятой.
Этот тест может бытьполезно для проверки наличия математических функций C99.
С указателями потенциально полезно выражение (1?0:(f)(0))
- оно оценивается как 0
(int
) или (void *)0)
(нулевой указатель)постоянная) в зависимости от типа возврата f
.Но мне еще предстоит найти какой-либо хитрый способ проверить, имеет ли выражение целочисленное значение или тип указателя.
Большая проблема, с которой я сталкиваюсь, состоит в том, что void *
не может участвовать в арифметике указателей и неявно не конвертируется вдругие типы указателей в арифметических контекстах.Например, если это произойдет, это сработает (слегка нарушая мои правила, касающиеся UB / IDB):
#define HAS_PROTO_PTR_RET_1_ARG(f) ((int)((char (*)[2])2 - (1?0:(f)(0))) == 1)
Есть идеи для решения этой проблемы?
Обновление: У меня есть решение, которое зависит только от того, что intmax_t
больше int
:
#define HAS_PROTO_PTR_RET_1_ARG(f) ( \
sizeof(int)!=sizeof(void *) ? sizeof ((f)(0)) == sizeof(void *) : \
sizeof (1?(intmax_t)0:(f)(0)) == sizeof(void *) )
Есть два случая.Если int
и void *
имеют разные размеры, мы просто проверяем размер возвращаемого значения.В противном случае int
и void *
имеют одинаковый размер, поэтому (по большому предположению) intmax_t
и void *
не имеют одинаковый размер.Мы создаем выражение, тип которого равен intmax_t
, если тип возвращаемого значения int
, и void *
, если тип возвращаемого значения void *
, и проверяем его размер.
Этот макрос завершается ошибкой только на машинах, гдеint
, intmax_t
и void *
имеют одинаковый размер.Практически говоря, это означает только на DSP с 64-битной или более int
.Поскольку почти все настоящие POSIX и POSIX-подобные системы имеют 32-битный int фиксированного размера и intmax_t
должен быть как минимум 64-битным, это достаточно портативно, чтобы сделать меня счастливым.