C11 _Generic 用法
C11 _Generic usage
我正在尝试学习如何使用 "new" C11 通用表达式,但我 运行 撞墙了。
考虑以下代码:
#include <stdlib.h>
#include <stdio.h>
#define test(X, Y, c) \
_Generic((X), \
double: _Generic((Y), \
double * : test_double, \
default: test_double \
), \
int: _Generic((Y), \
int * : test_int, \
default: test_int \
) \
) (X, Y, c)
int test_double(double a, double *b, int c);
int test_int(int a, int *b, int c);
int test_double(double a, double *b, int c) { return 1; }
int test_int(int a, int *b, int c) { return 2; }
int main()
{
double *t = malloc(sizeof(double));
int *s = malloc(sizeof(int));
int a1 = test(3.4, t, 1);
int i = 3;
int a2 = test(i, s, 1);
printf("%d\t", a1);
printf("%d\n", a2);
return 0;
}
一切正常,但我仍然不明白为什么“_Generic((Y), ...”中的那些默认情况是必要的,而我可以在“_Generic((X)”的末尾省略它, ..." 没有后果。
事实上,如果我删除这两个默认值,我会得到一个错误(gcc 5.4.0)说 "selector of type ‘double *’ is not compatible with any association" while macro-expanding " int a1 = test( 3.4, t, 1);"与 "int *" 相同,同时宏扩展 test(i, s, 1)
"default" 真的有必要吗?还是我遗漏了什么?
在第一种情况下,到底为什么会这样?如果我只有 test_double 和 test_int 可以调用,为什么我要为一些永远不应该编译的东西设置默认情况?
发生这种情况显然是因为嵌套的 _Generic 选择。
问题在于,对于_Generic,必须在编译时为所有可能的泛型关联满足类型兼容性。即使只选择了一个关联,但未选择的那些仍然必须有一些兼容的关联。
关联默认处理与该 _Generic 选择的其余关联不兼容的每个关联。
假设您删除了 int: _Generic((Y),
上的默认关联。如果这样做,则会选择 double 关联,但 int 关联仍必须处理 double* 类型,这通常是默认完成的。在这种情况下,只有 int* 关联,它会输出错误。
TL;DR
选择发生在编译时,但这 不 意味着其他(未选择的)代码被丢弃。它仍然必须有效,这意味着 ...
If default is not used and none of the type-names are compatible with the type of the controlling expression, the program will not compile.
这是一个令人惊讶的结果:
没有 "first Y" 的默认大小写:
#define test(X, Y, c) \
_Generic((X), \
double: _Generic((Y), \
double * : test_double \
), \
int: _Generic((Y), \
int * : test_int, \
default: test_default \
) \
) (X, Y, c)
我收到那个错误:
prog.c:6:30: error: '_Generic' selector of type 'int *' is not compatible with any association
请注意,它抱怨 int *
不兼容!为什么?
好吧,让我们看看报告的行:
int a2 = test(i, s, 1);
X
是 int
类型,Y
是 int *
.
类型
现在是重要的部分:扩展无条件发生。因此,即使 X
是 int
类型,X
的第一个关联(当它是 double
类型时)也必须是一个格式良好的程序。因此,Y
是 int *
时,以下内容必须格式正确:
_Generic((Y), \
double * : test_double \
), \
而且由于 int *
不是 double *
,事情就在这里中断了。
我只是在浏览标准(实际上是 N1570),但找不到任何 实际上准确指定此行为的内容 。我想在这种情况下可能会报告缺陷,标准对此过于模糊。我正在尝试这样做。
这是优先顺序。在您的代码中,两个 _Generic((Y)
在 _Generic((X)
之前是 运行。它们在括号中。编译器急于 运行 test(3.4, t, 1)
和 test(i, s, 1)
。
我会稍微重写一下代码。
#define test(X, Y, c) \
_Generic((X), \
double: _Generic((Y), \
double * : test_double, \
default : test_error \
), \
int: _Generic((Y), \
int * : test_int, \
default : test_error \
) \
) (X, Y, c)
static void test_error(void)
{
/* This function should be optimised away by compiler. */
assert(0);
}
不幸的是,_Generic
在标准中未指定。通常的解释似乎是未选择的情况下的表达式不能包含任何约束违规。
一个更简单的案例:
int main(void)
{
int x;
_Generic(0, int: x = 5, float: x = (void)0);
}
此代码在 gcc 中给出了约束违规,因为它对所有关联的表达式(而不仅仅是选定的表达式)执行约束检查,并且 x = (void)0
包含约束违规。
将此原则应用于没有默认大小写的代码,我们看到问题是当使用 Y
将宏实例化为声明为 int *s
的变量时,关联的表达式之一是 _Generic(s, double * : test_double)
,这是违反约束的,因为没有匹配的大小写。
我正在尝试学习如何使用 "new" C11 通用表达式,但我 运行 撞墙了。
考虑以下代码:
#include <stdlib.h>
#include <stdio.h>
#define test(X, Y, c) \
_Generic((X), \
double: _Generic((Y), \
double * : test_double, \
default: test_double \
), \
int: _Generic((Y), \
int * : test_int, \
default: test_int \
) \
) (X, Y, c)
int test_double(double a, double *b, int c);
int test_int(int a, int *b, int c);
int test_double(double a, double *b, int c) { return 1; }
int test_int(int a, int *b, int c) { return 2; }
int main()
{
double *t = malloc(sizeof(double));
int *s = malloc(sizeof(int));
int a1 = test(3.4, t, 1);
int i = 3;
int a2 = test(i, s, 1);
printf("%d\t", a1);
printf("%d\n", a2);
return 0;
}
一切正常,但我仍然不明白为什么“_Generic((Y), ...”中的那些默认情况是必要的,而我可以在“_Generic((X)”的末尾省略它, ..." 没有后果。
事实上,如果我删除这两个默认值,我会得到一个错误(gcc 5.4.0)说 "selector of type ‘double *’ is not compatible with any association" while macro-expanding " int a1 = test( 3.4, t, 1);"与 "int *" 相同,同时宏扩展 test(i, s, 1)
"default" 真的有必要吗?还是我遗漏了什么? 在第一种情况下,到底为什么会这样?如果我只有 test_double 和 test_int 可以调用,为什么我要为一些永远不应该编译的东西设置默认情况?
发生这种情况显然是因为嵌套的 _Generic 选择。
问题在于,对于_Generic,必须在编译时为所有可能的泛型关联满足类型兼容性。即使只选择了一个关联,但未选择的那些仍然必须有一些兼容的关联。
关联默认处理与该 _Generic 选择的其余关联不兼容的每个关联。
假设您删除了 int: _Generic((Y),
上的默认关联。如果这样做,则会选择 double 关联,但 int 关联仍必须处理 double* 类型,这通常是默认完成的。在这种情况下,只有 int* 关联,它会输出错误。
TL;DR
选择发生在编译时,但这 不 意味着其他(未选择的)代码被丢弃。它仍然必须有效,这意味着 ...
If default is not used and none of the type-names are compatible with the type of the controlling expression, the program will not compile.
这是一个令人惊讶的结果:
没有 "first Y" 的默认大小写:
#define test(X, Y, c) \
_Generic((X), \
double: _Generic((Y), \
double * : test_double \
), \
int: _Generic((Y), \
int * : test_int, \
default: test_default \
) \
) (X, Y, c)
我收到那个错误:
prog.c:6:30: error: '_Generic' selector of type 'int *' is not compatible with any association
请注意,它抱怨 int *
不兼容!为什么?
好吧,让我们看看报告的行:
int a2 = test(i, s, 1);
X
是 int
类型,Y
是 int *
.
现在是重要的部分:扩展无条件发生。因此,即使 X
是 int
类型,X
的第一个关联(当它是 double
类型时)也必须是一个格式良好的程序。因此,Y
是 int *
时,以下内容必须格式正确:
_Generic((Y), \
double * : test_double \
), \
而且由于 int *
不是 double *
,事情就在这里中断了。
我只是在浏览标准(实际上是 N1570),但找不到任何 实际上准确指定此行为的内容 。我想在这种情况下可能会报告缺陷,标准对此过于模糊。我正在尝试这样做。
这是优先顺序。在您的代码中,两个 _Generic((Y)
在 _Generic((X)
之前是 运行。它们在括号中。编译器急于 运行 test(3.4, t, 1)
和 test(i, s, 1)
。
我会稍微重写一下代码。
#define test(X, Y, c) \
_Generic((X), \
double: _Generic((Y), \
double * : test_double, \
default : test_error \
), \
int: _Generic((Y), \
int * : test_int, \
default : test_error \
) \
) (X, Y, c)
static void test_error(void)
{
/* This function should be optimised away by compiler. */
assert(0);
}
_Generic
在标准中未指定。通常的解释似乎是未选择的情况下的表达式不能包含任何约束违规。
一个更简单的案例:
int main(void)
{
int x;
_Generic(0, int: x = 5, float: x = (void)0);
}
此代码在 gcc 中给出了约束违规,因为它对所有关联的表达式(而不仅仅是选定的表达式)执行约束检查,并且 x = (void)0
包含约束违规。
将此原则应用于没有默认大小写的代码,我们看到问题是当使用 Y
将宏实例化为声明为 int *s
的变量时,关联的表达式之一是 _Generic(s, double * : test_double)
,这是违反约束的,因为没有匹配的大小写。