在C中的Typechecking宏参数

是否可以对#define宏进行类型检查? 例如:

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

上面的代码似乎不起作用。 我究竟做错了什么?

顺便说一下,我正在使用gcc,我可以保证在这个项目中我将一直使用gcc。 代码不需要是可移植的。

gcc支持typeof

例如,从linux内核中获取的类型安全的min宏

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

但它不允许你比较两种类型。 注意虽然会产生警告的指针比较 - 你可以做这样的类型检查(也来自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 } 

我确信有一些方法可以为此获得编译器错误。

不,宏不能为您提供任何类型检查。 但是,毕竟,为什么宏? 您可以编写一个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中的类型是否充满问题。

首先,在编译阶段通过文本替换扩展宏,其中没有可用的类型信息。 因此,编译器在进行宏扩展时检查参数的类型是完全不可能的。

其次,当您尝试在扩展代码中执行检查时,如问题中的assert ,您的检查将延迟到运行时,并且还会触发看似无害的构造,如

 a = read_16(REG16_A); 

因为枚举数( REG16_AREG16_BREG16_C )的类型是int而不是REG16类型。

如果您想要类型安全,最好的办法是使用一个function。 如果您的编译器支持它,您可以声明函数inline ,因此编译器知道您希望尽可能避免函数调用开销。