C11 中关于 _Generic 语句的歧义?

问题描述 投票:0回答:1

尽管我仔细研究了 C11 标准,但我看不到左值在 _Generic 表达式中作为控制表达式出现时是否会转换为右值的问题的解决方案。例如,以下函数返回 1 还是 0?

int func()
{
   const int x;
   return _Generic( x, int: 1, default: 0 );
}

在标准中,左值转换定义如下(6.3.2.1.2):

除非它是 sizeof 运算符、_Alignof 运算符、一元 & 运算符、++ 运算符、-- 运算符或 的左操作数的操作数。运算符或赋值运算符,将不具有数组类型的左值转换为指定对象中存储的值(并且不再是左值);这称为左值转换。如果左值具有限定类型,则该值具有左值类型的非限定版本;此外,如果左值具有原子类型,则该值具有左值类型的非原子版本;否则,该值具有左值的类型...

显然,func 返回 1。控制表达式“x”经历左值转换,因为它没有出现在一种例外情况中。因此,它的类型为 int 并且选择 1。

另一方面,标准指出(6.5.1.1.2):

...泛型关联中的类型名称应指定完整的对象类型,而不是可变修改类型...

和(6.3.2.1.3):

除非它是 sizeof 运算符、_Alignof 运算符或一元 & 运算符的操作数,或者是用于初始化数组的字符串文字,否则类型为 ''array of type'' 的表达式将转换为表达式类型“指向类型的指针”指向数组对象的初始元素并且不是左值...

我所看到的明确排除可变修改类型的唯一原因是允许数组但不允许可变长度数组(因为该类型已经要求是完整的对象类型)。由于似乎很清楚左值转换和指针转换要么都适用于 _Generic 控制表达式,要么都不适用,因此这表明不会发生转换。否则,排除可变修改类型是多余的并且极其令人困惑。

在我看来,这证明了左值转换仅隐式与计算语句相关的论点,并且不计算 _Generic 的控制表达式。根据这种理解,不存在左值转换,并且在给定的示例中,“x”具有其未转换的类型 const int,因此 func 返回 0。

标准中是否有任何内容澄清了这个问题?特别是, func 在任何符合要求的实现上是否具有相同的返回值?最后,流行的编译器(例如clang、gcc等)在这个问题上是否一致?

我应该注意,我正在使用该标准的委员会草案,因此如果最终版本澄清了这一点,请告诉我。

c generics c11 ambiguity
1个回答
0
投票

正如 @Jens Gustedt 在评论中指出的,这是 C11 中的一个已知问题,后来在 C17 中得到修复。 C17 6.5.1 §2 添加以下句子:

控制表达式的类型是表达式的类型,就像它经历了左值转换、数组到指针转换或函数到指针转换一样。

脚注进一步指出左值转换意味着类型限定符被删除。

因此,在 C17 或更高版本中,

_Generic( x, int: 1, default: 0 )
保证始终为
1
返回
const int x;
。如果您在关联列表中尝试类似
const int:
的操作,一些较新的编译器会发出警告。

© www.soinside.com 2019 - 2024. All rights reserved.