比特域与一个(负)整数,未定义的行为或编译器错误的比较?

这是一个小程序。 这应该打印0或1,还是有未定义的行为?

#include  struct S0 { unsigned f1 : 1; }; struct S0 s; int main (void) { int x = -3; int y = x >= (0, s.f1); printf ("%d\n", y); return 0; } 

这是从重新发布的CSmith测试中获得的, 这里将更详细地讨论这种情况。

特别是,GCC,KCC和CompCert输出0,而MSVC 2010,ICC 12.0.2和最近的Clang输出1。

有趣的问题。

根据C99草案标准6.5.17.1, (0, s.f1)的类型与s.f1的类型相同,其中(每6.7.2.1.9)是“由1位组成的无符号整数类型” 。 这是一种算术类型,因为它是一个整数类型,它的精度是1(每6.2.6.2.6,6.6.6.1.3意味着没有填充位),因此它的秩小于int级别(按照6.3.1.1.1下的第二项; int的精度至少为15,因为它必须能够表示-32767到32767范围内的值(见5.2.4.2.1))。

由于x和表达式(0, s.f1)都具有算术类型,因此执行通常的算术转换(按照6.5.8.3)。 由于int可以表示s.f1的全部值,因此它被提升为(signed)int(根据6.3.1.1.2)。 然后,因为两个操作数都是(带符号)整数,所以公共实数类型是signed int(按照6.3.1.8),因此比较结果应为0。

AFAIK, s.f1的类型是unsigned int 。 我相信逗号操作符是一个红鲱鱼; 该比较相当于int y = x >= s.f1; 。 应用“通常的算术转换”(C99 6.3.1.8),在进行比较时将x转换为unsigned int ; 这种转换是明确定义的(它将产生UINT_MAX-2 。因此它会更大。所以答案应该是1

我在这里补充一下,这是来自Rajan Bhakta的评论#39, 在这里 ,

这是标准中的模糊性,已在第6.3.1.1节第2节中即将出版的最新版ISO C标准(通常称为C1X,直到它被批准)中清除。实质上是位域类型(来自结果逗号表达式)转换为int,因此比较是带符号的int比较。 实质上,C1X标准表示y的值为0。

如果有人能证实这一点,我将不胜感激。