您如何将 _Generic 与在 C 中类型定义的结构一起使用?
How do you use _Generic with structs that are typedef-ed in C?
我是 C 的新手,目前正在通过在 C11 中使用 _Generic 探索函数重载的概念。
在 this SO post 中,@Lundin 提供了以下代码片段,我已经 运行 没有问题:
#include <stdio.h>
void func_int (int x) { printf("%d\n", x); }
void func_char (char ch) { printf("%c\n", ch); }
#define func(param) \
_Generic((param), \
int: func_int(param), \
char: func_char(param)); \
int main()
{
func(1);
func((char){'A'});
}
@Lundin 还提到了以下内容:
A much better way would be to make a function interface with a single
struct parameter, which can be adapted to contain all the necessary
parameters. With such an interface you can use the above simple method
based on _Generic. Type safe and maintainable.
所以我决定将上面的示例扩展到 structs
以查看实际效果。
以下是我的尝试:
#include <stdlib.h>
#include <stdio.h>
typedef struct args_int Args_int;
typedef struct args_char Args_char;
void func_int(Args_int args);
void func_char(Args_char args);
struct args_int {
int val;
};
struct args_char {
char val;
};
#define func(param)\
_Generic((param),\
Args_int: func_int(param),\
Args_char: func_char(param));
void func_int (Args_int args) {
printf("%d\n", args.val);
}
void func_char (Args_char args) {
printf("%c\n", args.val);
}
int main(void) {
Args_char args = {0};
args.val = 'A';
func(args);
}
然而,不幸的是,我收到以下编译错误,它抱怨说我在编译器期望 Args_int
时传入了 Args_char
。显然,我的意图是传递 Args_char
,我的期望是 func_char
作为结果被调用。
struct_args_by_val_executable.c:35:10: error: passing 'Args_char' (aka 'struct args_char') to parameter of incompatible type 'Args_int' (aka 'struct args_int')
func(args);
^~~~
struct_args_by_val_executable.c:20:28: note: expanded from macro 'func'
Args_int: func_int(param),\
^~~~~
struct_args_by_val_executable.c:24:25: note: passing argument to parameter 'args' here
void func_int (Args_int args) {
^
1 error generated.
为什么我的示例没有按预期工作?这里的解决方法是什么?
在相关说明中,我设法获得了一个“指向结构的指针”版本,没有任何问题,如下所示。但是,鉴于上面的编译错误,我觉得这可能是侥幸?
#include <stdio.h>
typedef struct args_int Args_int;
typedef struct args_char Args_char;
void func_int(Args_int *args);
void func_char(Args_char *args);
struct args_int {
int val;
};
struct args_char {
char val;
};
#define func(param)\
_Generic((param),\
Args_int*: func_int(param),\
Args_char*: func_char(param));
void func_int (Args_int *args) {
printf("%d\n", args->val);
}
void func_char (Args_char *args) {
printf("%c\n", args->val);
}
int main(void) {
Args_char args = {0};
args.val = 'A';
func(&args);
}
上面的输出符合预期:
A
问题是所有 _Generic
中使用的表达式必须有效。
在您的示例宏 func
扩展为:
int main(void) {
Args_char args = {0};
args.val = 'A';
_Generic(args,
Args_int: func_int(args),
Args_char: func_char(args));
}
请注意,将 func_int(args)
用于 args
即 Args_char
会导致错误。
解决方案是使用 _Generic
到 select 函数指针,然后对其应用参数。
#define func(param) \
_Generic((param), \
Args_int: func_int, \
Args_char: func_char) (param)
只是发布这个“记录”:
您在那里找到的实际上不是我的一个很好的代码示例!最好将参数列表包含在 _Generic
子句之外,就像 @tsanisl 在他们的回答中提到的那样(我接受那个作为你问题的答案)。这就是 C 委员会打算使用该功能的方式,您可以在标准本身中找到此类示例,例如 6.5.1:
#define cbrt(X) _Generic((X), \
long double: cbrtl, \
default: cbrt, \
float: cbrtf \
)(X)
您找到的代码片段是幸运的,因为 char
和 int
可以在“如同通过赋值”调用函数时相互转换。当使用两个无法隐式转换的不兼容类型时,宏将针对错误的类型进行错误扩展。
我现在已经更新 来使用这个:
#define func(param) \
_Generic((param), \
int: func_int, \
char: func_char)(param) \
我是 C 的新手,目前正在通过在 C11 中使用 _Generic 探索函数重载的概念。
在 this SO post 中,@Lundin 提供了以下代码片段,我已经 运行 没有问题:
#include <stdio.h>
void func_int (int x) { printf("%d\n", x); }
void func_char (char ch) { printf("%c\n", ch); }
#define func(param) \
_Generic((param), \
int: func_int(param), \
char: func_char(param)); \
int main()
{
func(1);
func((char){'A'});
}
@Lundin 还提到了以下内容:
A much better way would be to make a function interface with a single struct parameter, which can be adapted to contain all the necessary parameters. With such an interface you can use the above simple method based on _Generic. Type safe and maintainable.
所以我决定将上面的示例扩展到 structs
以查看实际效果。
以下是我的尝试:
#include <stdlib.h>
#include <stdio.h>
typedef struct args_int Args_int;
typedef struct args_char Args_char;
void func_int(Args_int args);
void func_char(Args_char args);
struct args_int {
int val;
};
struct args_char {
char val;
};
#define func(param)\
_Generic((param),\
Args_int: func_int(param),\
Args_char: func_char(param));
void func_int (Args_int args) {
printf("%d\n", args.val);
}
void func_char (Args_char args) {
printf("%c\n", args.val);
}
int main(void) {
Args_char args = {0};
args.val = 'A';
func(args);
}
然而,不幸的是,我收到以下编译错误,它抱怨说我在编译器期望 Args_int
时传入了 Args_char
。显然,我的意图是传递 Args_char
,我的期望是 func_char
作为结果被调用。
struct_args_by_val_executable.c:35:10: error: passing 'Args_char' (aka 'struct args_char') to parameter of incompatible type 'Args_int' (aka 'struct args_int')
func(args);
^~~~
struct_args_by_val_executable.c:20:28: note: expanded from macro 'func'
Args_int: func_int(param),\
^~~~~
struct_args_by_val_executable.c:24:25: note: passing argument to parameter 'args' here
void func_int (Args_int args) {
^
1 error generated.
为什么我的示例没有按预期工作?这里的解决方法是什么?
在相关说明中,我设法获得了一个“指向结构的指针”版本,没有任何问题,如下所示。但是,鉴于上面的编译错误,我觉得这可能是侥幸?
#include <stdio.h>
typedef struct args_int Args_int;
typedef struct args_char Args_char;
void func_int(Args_int *args);
void func_char(Args_char *args);
struct args_int {
int val;
};
struct args_char {
char val;
};
#define func(param)\
_Generic((param),\
Args_int*: func_int(param),\
Args_char*: func_char(param));
void func_int (Args_int *args) {
printf("%d\n", args->val);
}
void func_char (Args_char *args) {
printf("%c\n", args->val);
}
int main(void) {
Args_char args = {0};
args.val = 'A';
func(&args);
}
上面的输出符合预期:
A
问题是所有 _Generic
中使用的表达式必须有效。
在您的示例宏 func
扩展为:
int main(void) {
Args_char args = {0};
args.val = 'A';
_Generic(args,
Args_int: func_int(args),
Args_char: func_char(args));
}
请注意,将 func_int(args)
用于 args
即 Args_char
会导致错误。
解决方案是使用 _Generic
到 select 函数指针,然后对其应用参数。
#define func(param) \
_Generic((param), \
Args_int: func_int, \
Args_char: func_char) (param)
只是发布这个“记录”:
您在那里找到的实际上不是我的一个很好的代码示例!最好将参数列表包含在 _Generic
子句之外,就像 @tsanisl 在他们的回答中提到的那样(我接受那个作为你问题的答案)。这就是 C 委员会打算使用该功能的方式,您可以在标准本身中找到此类示例,例如 6.5.1:
#define cbrt(X) _Generic((X), \
long double: cbrtl, \
default: cbrt, \
float: cbrtf \
)(X)
您找到的代码片段是幸运的,因为 char
和 int
可以在“如同通过赋值”调用函数时相互转换。当使用两个无法隐式转换的不兼容类型时,宏将针对错误的类型进行错误扩展。
我现在已经更新 来使用这个:
#define func(param) \
_Generic((param), \
int: func_int, \
char: func_char)(param) \