Как проверить тип макроса C

Я думал о способах проверки типов в макросах C, и до сих пор лучшим способом, который я придумал, является следующее:

#define ASSERT_PTYPE(TYPE, VALUE) (0 && (*(int (*)(TYPE*))0)(VALUE))

Это, очевидно, ожидает имя типа и указатель на этот тип. Аналогичный макрос ASSERT_TYPE можно сделать также. Это похоже на работу с GCC. Это даже дает очень полезное сообщение об ошибке в случае, если типы не совпадают. Проблемы в том, что я не совсем уверен, что это действительно C или лучший способ для этого.

Как я понимаю, в стандарте говорится, что вы можете наложить указатель на функцию, но результат вызова указателя функции отливки undefined. В этом случае функция не может быть вызвана во время выполнения. Это достаточно хорошо или стандартное означает, что вы даже не можете писать код, который нельзя назвать вызывающим, который вызывает функцию трансляции?

Ответ 1

С C99 и составными литералами вы можете сделать что-то вроде

#define ASSERT_TYPE(TYPE, VALUE) ((TYPE){ 0 } = (VALUE))

Это гарантирует, что VALUE соответствует назначению TYPE. Выражение возвращает значение r из-за назначения.

Компонентные литералы работают в области функций, а также в области файлов, и любой достойный компилятор должен оптимизировать дополнительный объект, созданный в стороне.

Дополнение: TYPE в этом макросе может быть любое допустимое имя типа, например указатель double*, struct или union struct toto, кроме массивов. Тип массива, такой как double[4], не будет работать из-за назначения. Использовать указатель на массив double(*)[4], например, как в

double A[4];
(*ASSERT_TYPE(double(*)[4], &A))

где вторая строка снова является lvalue типа double[4], которая проверяет время компиляции для этого свойства.