有符号和无符号整数的整数转换等级

6

For example, If I have,

 int a = 42;
 unsigned b = 10;
 int c = a + b;

针对这个语句,int c = a + b; 是先将 a 转换为 unsigned int 还是将 b 转换为 signed int?因为 unsigned intsigned 具有相同的转换等级,所以我们如何知道哪一个会被转换?是否有标准规则?


@Jay:这个问题并不是那个问题的复制;这个问题询问的是选择转换规则的规定,而那个问题询问的是有符号到无符号的转换是否安全。 - Eric Postpischil
1个回答

10
简短回答:根据C99 6.3.1.8-p1,a的值将被转换成一个无符号整数,方法是根据C99 6.3.1.3-p2,将UINT_MAX+1加到它上面,直到它落在unsigned int允许的范围内。由于它已经在该范围内,因此不会执行任何加法操作。根据C99 6.3.1.3-p3,如果(p1)和(p2)不适用,则分配回int c的结果将是实现定义的。但在这种情况下,请注意6.3.1.3-p1中的“值”条款。 在这种情况下,值(52)可以由int表示,因此它不会改变,并且是定义的。

C99 6.3.1.3 有符号和无符号整数

  1. 当具有整数类型的值转换为除了_Bool以外的另一种整数类型时,如果该值可以用新类型表示,则该值保持不变。

  2. 否则,如果新类型是无符号的,则通过重复添加或减去可以在新类型中表示的最大值加1,直到该值处于新类型的范围内,将该值转换。

  3. 否则,新类型为有符号,该值无法在其中表示;结果要么是实现定义的,要么引发实现定义的信号。

C99 6.3.1.8 普通算术转换

许多要求算术类型操作数的运算符会以类似的方式进行转换并产生结果类型。 目的是确定操作数和结果的共同实际类型。 对于指定的操作数,每个操作数都将转换为相应实际类型为常见实际类型的类型,而无需更改类型域。 除非另有明确说明,否则如果它们是相同的,则公共实际类型也是操作数的类型域的结果对应实际类型,否则为复杂类型域。 这种模式称为“通常的算术转换”。
首先,如果任一操作数的对应实际类型为long double,则另一个操作数将转换为其对应实际类型为long double的类型,而不更改类型域。
否则,如果任一操作数的对应实际类型为double,则另一个操作数将转换为其对应实际类型为double的类型,而不更改类型域。
否则,如果任一操作数的对应实际类型为float,则另一个操作数将转换为其对应实际类型为float的类型,而不更改类型域。
否则,在两个操作数上执行整数提升。 然后将以下规则应用于提升的操作数:
- 如果两个操作数具有相同的类型,则无需进一步转换。 - 否则,如果两个操作数都具有有符号整数类型或两者都具有无符号整数类型,则具有较小的整数转换秩的操作数将转换为具有较大转换秩的操作数的类型。 - 否则,如果具有无符号整数类型的操作数的等级大于或等于其他操作数类型的等级,则具有有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型。 - 否则,如果具有有符号整数类型的操作数的类型可以表示无符号整数类型的所有值,则具有无符号整数类型的操作数将转换为具有有符号整数类型的操作数的类型。
  • 如果不是这种情况,那么两个操作数将被转换为带有有符号整数类型的操作数相应的无符号整数类型。


  • @EricPostpischil 是的先生,我刚想起来并在您发布此内容时进行了更新。我只熟悉标准的那一部分,是因为针对另一个问题的这篇最近的回答 - WhozCraig
    @user963241:这个答案似乎足够了,如果你不需要额外的解释,我不介意你接受它。 - Eric Postpischil
    1
    @WhozCraig: 关于“实现定义”,需要做什么?例如,符合规范的实现是否可以明确指定将signed char设置为超出范围-128到+127的值的效果将是一个其低位正确的值,而其高位可能任意变化,或者实现需要执行与高位一致的某些操作? - supercat
    1
    @WhozCraig:我对“实现定义”的理解至少在早期版本的规范中是,实现应该是一致的,但要求编译器始终执行越界转换可能会影响性能。考虑shortVar = uvar1 + uvar2;。如果shortVar在RAM中,这样的语句自然会截断上位比特,但如果它在寄存器中,让它截断上位比特可能需要额外的几个指令。符合标准的编译器是否需要添加这样的指令? - supercat
    @supercat 我已经点赞了这两条评论,因为我在没有对此事进行一些功课的情况下,实在不知道答案。我发现6.3.1.3-p3如何决定类型是有符号的并且该值无法保存其中很有趣。因此,这是实现定义的,标准没有指定结果值。在我的理解中,这意味着标准对所表示的值不做任何保证。因此,你的代码也不能。我认为,在这种情况下,符合标准的编译器不应该满足任何要求,除了指定类型的有符号性。 - WhozCraig
    显示剩余6条评论

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接