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 int
和 signed
具有相同的转换等级,所以我们如何知道哪一个会被转换?是否有标准规则?
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 int
和 signed
具有相同的转换等级,所以我们如何知道哪一个会被转换?是否有标准规则?
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 有符号和无符号整数
当具有整数类型的值转换为除了_Bool以外的另一种整数类型时,如果该值可以用新类型表示,则该值保持不变。
否则,如果新类型是无符号的,则通过重复添加或减去可以在新类型中表示的最大值加1,直到该值处于新类型的范围内,将该值转换。
否则,新类型为有符号,该值无法在其中表示;结果要么是实现定义的,要么引发实现定义的信号。
C99 6.3.1.8 普通算术转换
许多要求算术类型操作数的运算符会以类似的方式进行转换并产生结果类型。 目的是确定操作数和结果的共同实际类型。 对于指定的操作数,每个操作数都将转换为相应实际类型为常见实际类型的类型,而无需更改类型域。 除非另有明确说明,否则如果它们是相同的,则公共实际类型也是操作数的类型域的结果对应实际类型,否则为复杂类型域。 这种模式称为“通常的算术转换”。
首先,如果任一操作数的对应实际类型为long double,则另一个操作数将转换为其对应实际类型为long double的类型,而不更改类型域。
否则,如果任一操作数的对应实际类型为double,则另一个操作数将转换为其对应实际类型为double的类型,而不更改类型域。
否则,如果任一操作数的对应实际类型为float,则另一个操作数将转换为其对应实际类型为float的类型,而不更改类型域。
否则,在两个操作数上执行整数提升。 然后将以下规则应用于提升的操作数:
- 如果两个操作数具有相同的类型,则无需进一步转换。 - 否则,如果两个操作数都具有有符号整数类型或两者都具有无符号整数类型,则具有较小的整数转换秩的操作数将转换为具有较大转换秩的操作数的类型。 - 否则,如果具有无符号整数类型的操作数的等级大于或等于其他操作数类型的等级,则具有有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型。 - 否则,如果具有有符号整数类型的操作数的类型可以表示无符号整数类型的所有值,则具有无符号整数类型的操作数将转换为具有有符号整数类型的操作数的类型。如果不是这种情况,那么两个操作数将被转换为带有有符号整数类型的操作数相应的无符号整数类型。
signed char
设置为超出范围-128到+127的值的效果将是一个其低位正确的值,而其高位可能任意变化,或者实现需要执行与高位一致的某些操作? - supercatshortVar = uvar1 + uvar2;
。如果shortVar
在RAM中,这样的语句自然会截断上位比特,但如果它在寄存器中,让它截断上位比特可能需要额外的几个指令。符合标准的编译器是否需要添加这样的指令? - supercat