用于在ANSI C

时间:2015-11-07 11:24:05

标签: c compiler-errors c89 static-assert

问题

我尝试找到静态(编译时)断言,以确保(尽可能好)下面的事情。当我在自动代码生成环境中使用它们时(参见下面的“背景”),它们不必是整洁的,只需要打破编译,最好只需零开销。欢迎优雅的款式。

应检查以下事项:

类型标识

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 */

其中XT是C类型(包括结构化,聚合,对象指针,不是那么重要的函数指针)。再次注意,一组部分成功的解决方案也有帮助。

我认为某些解决方案部分可行:

  • 比较尺寸
  • 通过尝试取消引用来检查该类型是否为指针。
  • 表示无符号整数:使用预期的环绕值比较一个稍微变大的值。
  • 对于浮点数,将双精度精确可表示值与铸造值进行比较(希望最适合平台特定的舍入操作)

B变量具有全局范围

我的解决方案只是为了生成一个静态函数,它试图获取对全局变量的引用假设X是一个全局变量:

static void SA_IsGlobal_X() {(void) (&X == NULL); /* Dummy Operation */}

C A函数具有正确数量的参数

我还不知道。

D如果函数的原型是预期的

我还不知道。

E如果函数或宏参数是编译时常量(

这里讨论的问题是宏:

Macro for use in expression while enforcing its arguments to be compile time constants

对于函数,包装器宏可以这样做。

Z考虑到下面的“背景”部分,您可能想查看其他内容

首选的是可以使用C89完成的答案,在运行时,堆栈和(大多数编译器)代码大小都没有成本。由于检查将自动生成,因此可读性并不那么重要,但我希望尽可能将检查放在静态函数中。

背景

我想提供C函数和接口生成器,以便它们能够顺利地集成到不同的C框架中(C ++即将推出)。然后,接口生成器的用户仅指定输入的来源,以及哪个输出应该在哪里。选项至少是:

  • RAW(实施时 - 应该使用)
  • 来自接口函数参数,该参数的类型与我的输入/输出相同(可能是结构或数组元素的字段)
  • 来自getter / setter函数的
  • 来自全局变量
  • 使用编译时常量

我会:

  • 要求非常详细的接口规范(包括规范错误)
  • 使用解析器检查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 */
}

或者我将提供一段直接输入的代码(本地块) - 这是一个糟糕的架构,但如果我们不能足够快地放弃一些框架工作,可能是必要的,一些遗留脚本支持

1 个答案:

答案 0 :(得分:0)

对于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的解决方案在某些情况下失败....

顺便说一句,如果你计划在meanterm中使用C ++,你可以使用C ++模板等来完成这些谜题。会更加干净和可靠恕我直言。