如何将 _Generic 与 C 中类型定义的结构一起使用?

use*_*888 5 c generics struct overloading

我是 C 新手,目前正在通过在 C11 中使用 _Generic 来探索函数重载的概念。

这篇 SO 帖子中,@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'});
}
Run Code Online (Sandbox Code Playgroud)

@Lundin 还提到了以下内容:

更好的方法是使用单个结构参数创建一个函数接口,该结构参数可以适应包含所有必要的参数。有了这样的接口,你就可以使用上面基于_Generic的简单方法了。类型安全且可维护。

所以我决定扩展上面的例子来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);
}
Run Code Online (Sandbox Code Playgroud)

然而,不幸的是,我收到以下编译错误,该错误抱怨我在Args_char编译器期望Args_int. 显然,我的意图是通过考试,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.
Run Code Online (Sandbox Code Playgroud)

为什么我的示例没有按预期工作?这里的修复方法是什么?

在相关说明中,我设法获得了一个“指向结构的指针”版本,没有任何问题,如下所示。然而,考虑到上面的编译错误,我觉得这可能是一个侥幸?

#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);
}
Run Code Online (Sandbox Code Playgroud)

上面的输出符合预期:

A
Run Code Online (Sandbox Code Playgroud)

tst*_*isl 5

问题是中使用的所有_Generic表达式都必须有效。在您的示例中,宏func扩展为:

int main(void) {
    Args_char args = {0};
    args.val = 'A';
    _Generic(args,
             Args_int: func_int(args),
             Args_char: func_char(args));
}
Run Code Online (Sandbox Code Playgroud)

请注意,使用func_int(args)for argswhich isArgs_char会导致错误。

解决方案是使用_Generic选择一个函数指针,然后向其应用参数。

#define func(param)                       \
    _Generic((param),                     \
             Args_int: func_int,          \
             Args_char: func_char) (param)
Run Code Online (Sandbox Code Playgroud)