【发布时间】:2021-03-10 21:03:16
【问题描述】:
_Generic 可以根据传递的变量的类型在不同的语句之间进行选择,但是(正如预期的那样)如果这些语句本身包含类型名称,它将失败。举个例子:
#define PROMOTE(var) \
_Generic((var), \
char: int);
int main() {
char c;
PROMOTE(c) i = 0;
return 0;
}
人们可能期望上面的代码可以工作,使用PROMOTE 的行计算为“int i = 0”,但是很遗憾,它不能编译。我尝试了一些迂回的方法来编写类型 (int),例如使用宏 (#define TYPE_int int) 或 typedef (typedef int TYPE_int),但无济于事。这很可能是有意(或故意未定义)的行为,但我仍然对这种可能性感兴趣,即使它需要一些 C 魔法。
鉴于此,如何让_Generic 输出类型?
注意:解决方案应仅依赖于标准 C(即没有编译器特定的结构)。
【问题讨论】:
-
至于为什么你所做的不起作用,
generic association的第二部分是assignment expression。它不像宏那样进行令牌替换。 -
回复:“
_Generic可以在不同的语句之间切换”:不,不能。根据 C 2018 6.5.1.1 1,_Generic在表达式(标有类型)之间进行选择。 (从技术上讲,它们必须是语法中的 assignment-expression,它只是没有逗号运算符作为其顶部运算符的任何 expression。) -
C 标准使用Backus-Nauer form 或类似的东西来指定C 语言的语法。在各个小节中,标有“语法”的段落显示了该小节正在讨论的语法部分。
_Generic的语法见 C 2018 6.5.1.1 1,expression 和 assignment-expression 的语法见 6.5.17 和 6.5.16。int i = 0;不是表达式或语句;这是一个声明 (6.7)。表达式也不是语句,尽管后跟分号的表达式是 (6.8.3)。 -
6.5.1.1 中
_Generic的语法表明generic-selection 是_Generic(assignment-expression @987654339 @generic-assoc-list),generic-assoc-list是generic-association的逗号分隔列表,generic-association 是 type-name:assignment-expression。这就是我们知道_Generic在assignment-expression 项之间进行选择的方式。粗略地说,assignment-expression 是对赋值运算符之一的使用,=、*=、/=、%=、+=、-=、<<=、>>=、&=、^=或|=。它里面没有类型…… -
i = 0是一个赋值表达式。i = 0;是一个语句,它不是一个表达式。 (它确实包含一个表达式。)int i = 0;是一个声明,它不是语句或表达式。 (它不包含表达式,除了0本身或语句。)_Generic中只能有表达式,因此不能有语句或声明。