Выделение макрокоманд в C

Можно ли привести аргументы typecheck к макросу #define? Например:

typedef enum { REG16_A, REG16_B, REG16_C }REG16; #define read_16(reg16) read_register_16u(reg16); \ assert(typeof(reg16)==typeof(REG16)); 

Вышеприведенный код не работает. Что я делаю неправильно?

BTW, я использую gcc, и я могу гарантировать, что я всегда буду использовать gcc в этом проекте. Код не должен быть портативным.

gcc поддерживает typeof

например, миниатюрный макрос, полученный из ядра linux

 #define min(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x < _y ? _x : _y; }) 

но это не позволяет сравнивать два типа. Обратите внимание, хотя сравнение указателей, которое будет генерировать предупреждение, вы можете сделать typecheck, подобное этому (также из ядра linux)

 #define typecheck(type,x) \ ({ type __dummy; \ typeof(x) __dummy2; \ (void)(&__dummy == &__dummy2); \ 1; \ }) 

Предположительно, вы могли бы сделать что-то подобное - например, сравнить указатели на аргументы.

Проверка типов в C немного свободна для целочисленных типов; но вы можете обмануть компилятор, используя тот факт, что большинство типов указателей несовместимы.

Так

 #define CHECK_TYPE(var,type) { __typeof(var) *__tmp; __tmp = (type *)NULL; } 

Это даст предупреждение «назначение из несовместимого типа указателя», если типы не совпадают. Например

 typedef enum { A1,B1,C1 } my_enum_t; int main (int argc, char *argv) { my_enum_t x; int y; CHECK_TYPE(x,my_enum_t); // passes silently CHECK_TYPE(y,my_enum_t); // assignment from incompatible pointer type } 

Я уверен, что есть какой-то способ получить ошибку компилятора для этого.

Нет, macros не могут предоставить вам проверку типов. Но, в конце концов, почему макрос? Вы можете написать static inline функцию, которая (возможно) будет встроена в компилятор – и здесь вы будете иметь проверку типов.

 static inline void read_16(REG16 reg16) { read_register_16u(reg16); } 

Чтобы продолжить идею ulidtko, возьмите inline функцию и верните что-нибудь:

 inline bool isREG16(REG16 x) { return true; } 

С помощью таких вещей вы можете сделать компиляцию утверждений времени:

 typedef char testit[sizeof(isREG16(yourVariable))]; 

Нет. Макросы в C по своей природе являются небезопасными, и попытка проверки типов на C чревата проблемами.

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

Во-вторых, когда вы пытаетесь выполнить проверку расширенного кода, например, assert в вопросе, ваш чек откладывается на время выполнения, а также запускается на казалось бы безобидных конструкциях, таких как

 a = read_16(REG16_A); 

потому что REG16_A ( REG16_A , REG16_B и REG16_C ) имеют тип int а не тип REG16 .

Если вам нужна безопасность типа, лучше всего использовать функцию. Если ваш компилятор поддерживает его, вы можете объявить функцию inline , поэтому компилятор знает, что вы хотите избежать накладных расходов функции-функции, где это возможно.