C宏中的类型检查

oxcyiej7  于 2023-02-21  发布在  其他
关注(0)|答案(2)|浏览(122)

我试图在编译时对我的一个宏进行类型检查,简化后的代码如下所示:
我的结构包括:

  • 表示函数接口的类型的int,以及
  • 泛型函数指针
typedef void(*generic_func_t)(void);

typedef struct
{
     int            type;
     generic_func_t function;
} func_def_t;

为了初始化这个结构,我定义了两个宏;

#define INIT_FUNC1_TYPE(function) {1, (generic_func_t)function}
#define INIT_FUNC2_TYPE(function) {2, (generic_func_t)function}

其用法大致如下:

int(*func1_t)(int, int, int);
int(*func2_t)(int, int);

int foo(int a, int b)
{
   return a + b;
}

func_def_t active_func = INIT_FUNC2_TYPE(foo);

...

int a = 2;
int b = 3;
int c = 4;
int d;

if (active_func.type == 1)
{
   func1_t func = (func1_t)active_func.function;
   d = func(a, b, c);
}

if (active_func.type == 2)
{
   func2_t func = (func2_t)active_func.function;
   d = func(a, b);
}

我现在的问题是,任何类型的函数都可以强制转换为(void *)。
但是,必须以某种方式设计宏,使编译器只接受某种类型的函数接口,也许用typeof?
假设有以下函数类型:

void(*func1_t)(int, int, int);
int(*func2_t)(float, int);

我该怎么做呢?
编辑:我将指针从void * 改为generic_func_t,但问题的本质保持不变。宏INIT_FUNC1_TYPE应该只接受具有类似func1_t的接口的函数。宏INIT_FUNC2_TYPE应该只接受具有类似func2_t的接口的函数。

4nkexdtk

4nkexdtk1#

我的结构包括:

  • 表示函数接口的类型的int,以及
  • 指向函数的空指针

不,你没有,因为void *指向的是一个 * 对象 * 而不是一个函数。然而,你可以在函数指针类型之间自由转换(通过类型转换),所以你可以根据自己的需要选择任何一个 * 真正的 * 函数指针类型。

typedef struct {
     int  type;
     void (*function)(void);
} func_def_t;

无论如何,您都需要转换回正确的函数指针类型来调用函数,因此这并不比void *更难使用。
我现在的问题是,任何类型的函数都可以强制转换为(void )。
好吧,
没有 * 类型的函数指针可以被严格符合的程序强制转换为void *,但是如果你的编译器接受这样的转换作为扩展,那么是的,大概它可以为任何函数指针类型工作,从任何函数指针类型转换为任何其他函数指针类型也是如此,包括在严格符合的程序中。
但是,必须以某种方式设计宏,使编译器只接受某种类型的函数接口,也许用typeof?
标准C没有typeof,尽管我相信它计划包含在C23中,但我认为这对您没有帮助。
然而,你可以在宏中使用一个泛型表达式来限制它只能使用特定的函数指针类型。事实上,这样你就可以用一个宏来代替两个宏。
每种类型示例:

typedef void (func)(void);
typedef struct {
     int  type;
     func *function;
} func_def_t;

#define INIT_FUNC1_TYPE(f) {1, _Generic((f), void (*)(int, int, int) : (func *) f) }
#define INIT_FUNC2_TYPE(f) {2, _Generic((f), int (*)(float, int) : (func *) f) }

如果调用其中一个宏时使用的参数与内_Generic选择中的类型名称不匹配,并且每个类型名称仅提供一个选项,则编译器将予以反对。
但是,这样就错过了用一个宏做所有事情的机会。

#define INIT_FUNC_TYPE(f) { \
    .type = _Generic((f), \
        void (*)(int, int, int) : 1, \
        int (*)(float, int)     : 2), \
    .function = (func *) f \
}

现在(一个)宏根据宏参数的类型选择函数类型键(编译器拒绝与任何指定类型不匹配的参数),这比要求每个支持的函数签名都有一个单独的宏的方法更好地扩展。

qgzx9mmu

qgzx9mmu2#

C语言中的宏是简单的文本替换,完全忽略了C语言的类型。如果你想要类型检查,你必须声明结构体的成员为函数指针,就像这样

typedef struct
{
     int  type;
     void *(function) (int,int,int);
} func_def_t;

相关问题