7

我有以下 C 代码:

unsigned int a;
unsigned char b, c;
void test(void) {
    if (a < b)
        return;
    if (a < (b ? b : c))
        return;
}

当我编译它时(使用 Microsoft cl,来自 MS SDK 7,-W3警告级别),第二个比较发出警告:C4018,有符号/无符号不匹配。第一次比较不会发出警告。

我已经检查了条件运算符的 MS 文档,他们说如果两个操作数属于同一类型,则结果将属于同一类型,因此它应该作为第一个比较。我错过了什么吗?

UPD:经过测试,gcc -Wall -Wextra -pedantic没有收到任何警告。

4

3 回答 3

7

这可能是由于算术转换规则:首先,任何小于int(eg unsigned char) 的整数类型的转换等级都将提升为intor unsigned int

结果是否intunsigned int直接)取决于原始类型的有符号性,但其范围:int即使可以表示所有值,也可用于无符号类型,这是unsigned char主流架构的情况。

其次,由于两个操作数最终具有相同的转换等级,但一个是无符号的,另一个操作数也将转换为无符号类型。

从语义上讲,您的表达方式为

a < (unsigned int)(int)b

a < (unsigned int)(b ? (int)b : (int)c)

编译器显然足够聪明,可以注意到第一种情况不会导致问题,但第二种情况会失败。

Steve Jessop 的评论很好地解释了这是如何发生的:

我想在第一种情况下,编译器会认为,“我有一个比较运算符,其操作数类型是unsigned intand unsigned char。不需要警告,现在让我们应用提升,然后进行通常的转换”。

在第二种情况下,它认为,“我有一个比较运算符,其操作数类型是unsigned intand int(我将其作为 RHS 上的条件表达式的类型派生出来)。最好警告一下!”。

于 2012-10-11T11:06:20.563 回答
3

if (a < b)等于伪if (unsigned int < unsigned char)

每当在表达式中使用 char 类型时,C 中的整数提升规则都会将其隐式转换为int. 完成后,你有

if (unsigned int < int).

每当在表达式中使用两个具有相同等级但不同符号的整数时,有符号的整数就会隐式转换为无符号的。这是由通常的算术转换决定的,也就是平衡

所以你的第一个表达式被转换为

if (unsigned int < unsigned int)

在任何事情完成之前。


在第二个表达式中,我们有if (a < (b ? b : c))等于伪

if (unsigned int < (unsigned char ? unsigned char : unsigned char)).

对所有字符执行整数提升,因此它被隐式转换为

if (unsigned int < (int ? int : int)).

然后,条件运算符的一个奇怪而晦涩的规则规定 ?: 运算符的第二个和第三个运算符必须与通常的算术转换保持平衡。在这种情况下,它们已经属于同一类型,所以什么也不会发生。我们最终得到

if (unsigned int < int)

再次发生平衡,结果将被评估为

if (unsigned int < unsigned int)


当我用微软编译它时

当你用微软编译时,所有的赌注都没有了,他们的编译器在遵循标准方面很差。期待奇怪的、不合逻辑的警告。

于 2012-10-11T11:11:50.487 回答
1

C 和 C++ 之间的规则不同。使用 MSVC 编译 C 时可能很难判断适当的标准,但幸运的是在这种情况下 C89 和 C99 是相同的。

在 C89 3.3.15 中:

如果第二个和第三个操作数都具有算术类型,则执行通常的算术转换以将它们转换为通用类型并且结果具有该类型

在 C99 6.5.15/5 中:

如果第二个和第三个操作数都具有算术类型,则将由通常的算术转换确定的结果类型(如果它们应用于这两个操作数)就是结果的类型。

在 C++03 5.16/4 中:

如果第二个和第三个操作数是左值并且具有相同的类型,则结果是该类型并且是左值

因此,当您说“如果两个操作数属于同一类型,则结果将属于同一类型,因此它应该作为第一个比较”,这仅适用于 C++,不适用于 C。在 C 中该比较的 RHS 是int. 在 C++ 中,RHS 将是unsigned char您所期望的类型的左值。

于 2012-10-11T11:40:10.277 回答