英文:
type checking in C macro
问题
以下是您提供的文本的翻译部分:
I'm trying to do a type check at compile time in one of my macros. The simplified code looks something like this:
我正在尝试在我的宏之一中进行编译时的类型检查。简化后的代码如下:
I have a structure consisting of:
- an int representing a type of a function interface and
- a generic function pointer
我有一个由以下组成的结构:
- 一个整数,代表函数接口的类型,以及
- 一个通用函数指针
typedef void (*generic_func_t)(void);
typedef struct
{
int type;
generic_func_t function;
} func_def_t;
to initialize this structure I have defined two macros;
为了初始化这个结构,我定义了两个宏;
#define INIT_FUNC1_TYPE(function) {1, (generic_func_t)function}
#define INIT_FUNC2_TYPE(function) {2, (generic_func_t)function}
The usage would be something like this:
使用方式如下:
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);
}
My problem now is that any type of function can be cast to (void*).
但现在我的问题是,任何类型的函数都可以强制转换为(void*)。
But it must somehow be possible to design the macro in such a way that only a certain type of function-interface is accepted by the compiler. Maybe with typeof?
但必须以某种方式设计宏,以便编译器只接受特定类型的函数接口。也许可以使用typeof?
Let's say there are the function types:
假设存在以下函数类型:
void (*func1_t)(int, int, int);
int (*func2_t)(float, int);
How can I do that?
如何做到这一点?
Edited:
I changed the pointer from void* to generic_func_t but the essence of the questions stays the same. The macro INIT_FUNC1_TYPE should only accept functions with an interface like func1_t. The macro INIT_FUNC2_TYPE should only accept functions with an interface like func2_t.
编辑:
我将指针从void*更改为generic_func_t,但问题的本质保持不变。宏INIT_FUNC1_TYPE应该只接受具有类似func1_t的接口的函数。宏INIT_FUNC2_TYPE应该只接受具有类似func2_t的接口的函数。
英文:
I'm trying to do a type check at compile time in one of my macros. The simplified code looks something like this:
I have a structure consisting of:
- an int representing a type of a function interface and
- a generic function pointer
typedef void(*generic_func_t)(void);
typedef struct
{
int type;
generic_func_t function;
} func_def_t;
to initialize this structure I have defined two macros;
#define INIT_FUNC1_TYPE(function) {1, (generic_func_t)function}
#define INIT_FUNC2_TYPE(function) {2, (generic_func_t)function}
The usage would be something like this:
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);
}
My problem now is that any type of function can be cast to (void*).
But it must somehow be possible to design the macro in such a way that only a certain type of function-interface is accepted by the compiler. Maybe with typeof?
Let's say there are the function types:
void(*func1_t)(int, int, int);
int(*func2_t)(float, int);
How can I do that?
Edited:
I changed the pointer from void* to generic_func_t but the essence of the questions stays the same. The macro INIT_FUNC1_TYPE should only accept functions with an interface like func1_t. The macro INIT_FUNC2_TYPE should only accept functions with an interface like func2_t.
答案1
得分: 2
> 我有一个结构,包括:
>
> - 一个表示函数接口类型的int和
> - 函数的void指针
不,你没有,因为void *
指向一个对象而不是一个函数。但是,你可以自由地(通过类型转换)在函数指针类型之间转换,因此你可以为你的目的选择任何真正的函数指针类型。也许是 void (*)(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 \
}
现在(唯一的)宏根据宏参数的类型选择函数类型键(并且编译器会拒绝不匹配任何指定类型的参数)。这比需要为每个支持的函数签名单独创建一个宏的方法更具扩展性。
英文:
> I have a structure consisting of:
>
> - an int representing a type of a function interface and
> - a void pointer to the function
No, you haven't, because a void *
points to an object not a function. However, you can convert freely (via typecast) among function pointer types, so you can choose any bona fide function pointer type for your purpose. Perhaps void (*)(void)
:
typedef struct {
int type;
void (*function)(void);
} func_def_t;
You will need to convert back to the correct function pointer type to call the function anyway, so this is no harder to use than void *
.
> My problem now is that any type of function can be cast to (void*).
Well, no type of function pointer can be cast to void *
by a strictly conforming program. But if your compiler accepts such conversions as an extension then yes, presumably it works for any function pointer type. And so does converting from any function pointer type to any other function pointer type, including in strictly conforming programs.
> But it must somehow be possible to design the macro in such a way that only a certain type of function-interface is accepted by the compiler. Maybe with typeof?
Standard C does not have typeof
, though I believe it's scheduled for inclusion in C23. But I don't think that helps you.
However, you can use a type-generic expression in your macro to limit it to certain function pointer types. In fact, that could allow you to have a single macro instead of two.
Per-type example:
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) }
The compiler will object if one of those macros is invoked with an argument that does not match one of the type names in the _Generic
selection within, and each of those affords exactly one option.
But that misses out on the opportunity to do everything with a single macro. Consider this:
#define INIT_FUNC_TYPE(f) { \
.type = _Generic((f), \
void (*)(int, int, int) : 1, \
int (*)(float, int) : 2), \
.function = (func *) f \
}
Now the (one) macro chooses the function-type key based on the type of the macro argument (and the compiler rejects arguments that don't match any of the specified types). This scales better than an approach requiring a separate macro for each supported function signature.
答案2
得分: 1
宏在C语言中是简单的文本替换,完全不了解C类型。如果您想要类型检查,您将需要将结构体的成员声明为函数指针,如下所示:
typedef struct
{
int type;
void *(*function)(int, int, int);
} func_def_t;
英文:
Macros in C are simple text replacements and completely oblivious to C types. If you want type checking, you'll have to declare the member of the struct as a function pointer, like so
typedef struct
{
int type;
void *(function) (int,int,int);
} func_def_t;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论