问题
我试图找到静态(编译时)断言,以确保(尽可能好地)下面的事情。当我在自动代码生成上下文中使用它们时(请参阅下面的“背景”),它们不必整洁,只需要中断编译,最好是零开销。不过,我们欢迎优雅的变体。
应检查以下内容:
类型标识
typedef T T1;
typedef T T2;
typedef X T3;
T1 a;
T2 b;
T3 c;
SA_M1(T1,T2); /* compilation */
SA_M1(T1,T3); /* compilation error */
SA_M2(a,b); /* compilation */
SA_M2(a,c); /* compilation error */
其中 X
和 T
是 C 类型(包括结构化、聚合、对象指针,不是那么重要的函数指针)。再次注意,一组部分成功的解决方案也有帮助。
我假设的一些解决方案将部分起作用:
- 比较尺寸
- 通过尝试取消引用来检查该类型是否为声明的指针。
- 对于无符号整数:将略微转换为大的值与预期的环绕值进行比较。
- 对于 float ,将 double 精确表示值与类型转换值进行比较(希望平台特定的舍入操作最好)
B 变量具有全局作用域
目前我的解决方案是简单地生成一个静态函数,它试图获取对全局变量的引用假设 X
是一个全局变量:
static void SA_IsGlobal_X() {(void) (&X == NULL); /* Dummy Operation */}
C 函数具有正确数量的参数
我还不知道。
D 如果一个函数的原型(prototype)符合预期
我还不知道。
E 如果函数或宏参数是编译时常量(
这里针对宏讨论这个问题:
Macro for use in expression while enforcing its arguments to be compile time constants
对于函数,包装器宏可以做到。
Z 考虑到下面的“背景”部分,您可能想检查的其他事项
首选的是可以使用 C89 完成的答案,在运行时、堆栈和(对于大多数编译器)代码大小方面成本为零。由于检查将自动生成,因此可读性并不那么重要,但我喜欢尽可能将检查放在静态函数中。
背景:
我想提供 C 函数和接口(interface)生成器,以允许它们顺利地集成到不同的 C 框架中(即将推出 C++)。界面生成器的用户然后仅指定输入来自何处,以及哪些输出应该去往何处。选项至少是:
- RAW(已实现 - 应该使用)
- 来自接口(interface)函数参数,它是一种据说与我的输入/输出相同的类型(可能是结构或数组元素的字段)
- 来自 getter/setter 函数
- 来自全局变量
- 使用编译时间常数
我会:
- 要求非常详细的接口(interface)规范(包括规范错误)
- 使用解析器检查 typedef 和声明(包括工具错误和我的工具使用错误)
但这发生在生成时。除此之外:如果用户更改环境或采用我的函数的新主要版本(这可以通过宏检查版本来解决),而无需再次运行界面生成器,我希望在编译时有最后一道防线.
几代人的结果代码可能接近最坏的情况:
#include "IFMyFunc.h" /* contains all user headers for the target framework(s) */
#include "MyFunc.h"
RetType IFMYFunc(const T1 a, const struct T2 * const s, T3 * const c)
{
/* CHECK INTERFACE */
CheckIFMyFunc();
/* get d over a worst case parametrized getter function */
const MyD_type d = getD(s->dInfo);
/* do horrible call by value and reference stuff, f and g are global vars */
c.c1 = MyFunc(a,s->b,c.c1,d,f,&(c->c2), &e,&g);
set(e);
/* return something by return value */
return e;
}
(我很确定我会限制组合)。
static void CheckIFMyFunc(void)
{
/* many many compile time checks of types and specifications */
}
或者我将提供一段直接注入(inject)的代码(本地 block )——这是一个可怕的架构,但如果我们不能足够快地放弃一些由一些遗留脚本支持的框架工作,则可能是必要的。
最佳答案
对于A,会提议:
#define SA_M1(A, B) \
do { \
A ___a; \
B ___b = ___a; \
(void)___b; \
} while (0)
对于 D(我会说 C 已经由 D 完成)
typedef int (*myproto)(int a, char **c);
#define FN_SA(Ref, Challenger) \
do { \
Ref ___f = Challenger; \
(void) ___f; \
} while (0)
void test(int argc, char **argv);
int main(int argc, char **argv)
{
FN_SA(myproto, main);
FN_SA(myproto, test); /* Does not compile */
return 0;
}
然而,void * 仍然存在一些问题: 在 C 中,任何指针都可以转换为 void *,这可能会使 A 的解决方案在某些情况下失败....
顺便说一句,如果您打算在此期间使用 C++,您可以只使用 C++ 模板等来完成此测试。恕我直言,会更加干净可靠。
关于c - 用于识别 ANSI C 中损坏的自动生成接口(interface)层的静态断言,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33582185/