这是一个老问题,但我相信我有一个一般性的答案,根据Compiler Explorer 似乎可以在 MSVC、gcc 和 clang 上工作。
#define CHECK_TYPE(type,var) { typedef void (*type_t)(type); type_t tmp = (type_t)0; if(0) tmp(var);}
在每种情况下,如果类型不兼容,编译器都会生成有用的错误消息。这是因为它强加了用于函数参数的相同类型检查规则。
它甚至可以在同一范围内多次使用而不会出现问题。这部分让我有些吃惊。 (我认为我必须利用“__LINE__”来获得这种行为)
下面是我运行的完整测试,注释掉的行都会产生错误。
#include <stdio.h>
#define CHECK_TYPE(type,var) { typedef void (*type_t)(type); type_t tmp = (type_t)0; if(0) tmp(var);}
typedef struct test_struct
{
char data;
} test_t;
typedef struct test2_struct
{
char data;
} test2_t;
typedef enum states
{
STATE0,
STATE1
} states_t;
int main(int argc, char ** argv)
{
test_t * var = NULL;
int i;
states_t s;
float f;
CHECK_TYPE(void *, var); //will pass for any pointer type
CHECK_TYPE(test_t *, var);
//CHECK_TYPE(int, var);
//CHECK_TYPE(int *, var);
//CHECK_TYPE(test2_t, var);
//CHECK_TYPE(test2_t *, var);
//CHECK_TYPE(states_t, var);
CHECK_TYPE(int, i);
//CHECK_TYPE(void *, i);
CHECK_TYPE(int, s); //int can be implicitly used instead of enum
//CHECK_TYPE(void *, s);
CHECK_TYPE(float, s); //MSVC warning only, gcc and clang allow promotion
//CHECK_TYPE(float *, s);
CHECK_TYPE(float, f);
//CHECK_TYPE(states_t, f);
printf("hello world\r\n");
}
在每种情况下,带有 -O1 及更高版本的编译器都会删除结果代码中宏的所有痕迹。
使用 -O0 MSVC 将对函数的调用保留为零,但它在无条件跳转中被敲击,这意味着这不应该是一个问题。带有 -O0 的 gcc 和 clang 都删除了除了 tmp 变量的堆栈初始化为零之外的所有内容。