2011-03-18 41 views
10

我一直在思考的方式来验证类型C宏,到目前为止,我想出最好的办法是这样的:如何在C宏验证类型

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

这显然需要一个类型名称和指向该类型的指针。类似的ASSERT_TYPE宏也可以被创建。这似乎与海湾合作委员会工作得很好。它甚至在类型不匹配的情况下给出非常有用的错误消息。问题是,我不完全确定这是有效的C还是此事的最佳方式。

据我所知,标准说你可以投一个函数指针,但调用该函数指针的结果是未定义的。在这种情况下,在运行时调用函数是不可能的。这是否足够好或者标准是否意味着您甚至无法编写无法调用的调用cast函数的代码?

+0

不错的问题,这里是一个可能的C++对应http://stackoverflow.com/questions/5237163/how-does-the-following-code-work – JoeSlav 2011-03-18 09:01:06

+0

问题是...什么样的情况存在于C程序员的地方不知道传递给该宏的类型?代码有什么用处?此外,这些解决了与C语言中的许多隐式类型转换相关的任何问题。就C而言,例如,有符号和无符号是兼容的。 – Lundin 2011-03-18 12:43:10

回答

7

随着C99和复合文字,你可以这样做

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

这确保了VALUE是分配给TYPE兼容。由于赋值,表达式返回一个右值。

复合文字在函数范围以及文件范围内工作,任何体面的编译器都应该优化创建的额外对象。

加成TYPE在该宏可以是任何有效类型名称,e.g指针double*,结构或联合struct toto,除了阵列。阵列类型(如double[4])因分配而不起作用。使用指针 阵列double(*)[4]代替,e.g如

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

,其中第二线是再次double[4]类型的左值是编译时检查该属性。

+0

它不应该读'(TYPE *){0}',因为他想断言'VALUE'具有类型_pointer_到'TYPE'(宏的名字是'ASSERT_PTYPE'而不是'ASSERT_TYPE')? – Curd 2011-03-18 09:48:32

+0

@Curd,不,建议的解决方案适用于任何类型,不仅指针类型。我将其更名为'ASSERT_TYPE'以使其更清晰。要使用它作为指针类型,你只需要将这样的指针类型作为第一个参数,比如'double *'或其他类型。 – 2011-03-18 12:27:27

+0

这正是我想要得到的。这里唯一的缺点是错误信息稍微偏离了你从伪函数调用中获得的那一点。另外,在他的使用示例中,我认为你的意思是宏返回的右值不是左值吗? – ltc 2011-03-18 20:34:07