Как проверить тип в макросе C - PullRequest
10 голосов
/ 18 марта 2011

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

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

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

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

1 Ответ

7 голосов
/ 18 марта 2011

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

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

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

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

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

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

...