我试图学习如何使用“新”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),它说“类型为‘double*’的选择器不兼容任何关联”,即“宏展开时"int a1 = test(3.4,t,1);在宏展开测试时使用”int *“(i,s,1)。
“默认”真的有必要吗?还是我遗漏了什么?在第一种情况下,为什么要这样呢?如果我只有可以调用的test_double和test_int,为什么我应该为一些根本不应该编译的东西设置默认的大小写呢?
发布于 2016-10-17 22:47:50
TL;DR
选择发生在编译时,但是不意味着其他(未选中)代码被丢弃。它仍然是有效的,这意味着.
如果未使用默认值,且没有任何类型名称与控制表达式的类型兼容,则程序将不会编译。
(来源)
这是一个令人惊讶的问题:
没有默认情况下的“第一个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:错误:'_Generic‘类型的选择器'int *’与任何关联都不兼容
注意,它抱怨一个不兼容的int *!为什么?好吧,让我们来看看报道的台词:
int a2 = test(i, s, 1);X为int型,Y为int *型。
现在来了一个重要的部分:扩展发生unconditionally.因此,即使X是int类型的,X的第一个关联(当它是double类型时)必须是一个格式良好的程序。因此,如果Y是一个int *,那么必须有良好的格式:
_Generic((Y), \
double * : test_double \
), \既然int *不是double *,事情就会在这里破裂。
不过,我只是浏览了一下标准(实际上是N1570),却找不到任何具体指定这种行为的东西。我想在这种情况下,我们可以报告一个缺陷,这个标准太模糊了。我现在正试着这么做。
发布于 2016-10-18 00:32:06
不幸的是,_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),这是一个约束冲突,因为没有匹配的大小写。
发布于 2016-10-17 22:44:38
显然,这是因为嵌套的_Generic选择。
问题是,对于_Generic,必须在编译时满足所有可能的泛型关联的类型兼容性。即使只选择一个关联,但未选中的关联仍必须具有一些兼容的关联。
关联默认处理与该_Generic选择的其他关联不兼容的每个关联。
假设您删除了int: _Generic((Y),上的默认关联。如果这样做,则选择双重关联,但int关联仍然必须处理double*类型,这通常是默认情况下完成的。在这种情况下,只有int*关联,它输出一个错误。
https://stackoverflow.com/questions/40096584
复制相似问题