减去两个无符号变量,我希望得到无符号结果。我确实意识到会发生溢出,但是没关系,我实际上是指望它。 似乎并非需要将结果用于其他操作时。这是标准行为还是未定义行为?
uint8_t n1 = 255;
uint8_t z = 0;
uint8_t n = 1;
printf("n1 is %" PRIu8 "\n", n1);
printf("z - n is %" PRIu8 "\n", z - n);
printf("n1 < z: %s\n", n1 < z ? "yes" : "no");
printf("z - n < z: %s\n", z - n < z ? "yes" : "no");
printf("(uint8_t)(z - n) < (uint8_t)z: %s\n", (uint8_t)(z - n) < (uint8_t)z ? "yes" : "no");
输出:
n1 is 255
z - n is 255
n1 < z: no
z - n < z: yes
(uint8_t)(z - n) < (uint8_t)z: no
答案 0 :(得分:6)
当变量的类型为uint8_t
时,它们都被提升为(有符号的)int
,然后在提升的值之间进行减法运算,得到一个(有符号的)int
值。这是强制性的行为。
在C11中,§6.3.1.8 Usual arithmetic conversions说:
许多期望算术类型的操作数的运算符都以类似的方式引起转换并产生结果类型。目的是确定操作数和结果的通用实型。对于指定的操作数,在不更改类型域的情况下,将每个操作数转换为其对应的实型为普通实型的类型。除非另有明确说明,否则普通实型也是结果的相应实型,如果操作数相同,则其类型域为操作数的类型域,否则为复杂。这种模式称为通常的算术转换:
- 首先,如果一个操作数的相应实型为
long double
,则另一个操作数将在不改变类型域的情况下转换为相应的实型为long double
的类型。- 否则,如果一个操作数的相应实型为
double
,则另一个操作数将在不更改类型域的情况下转换为其相应实型为double
的类型。- 否则,如果每个操作数的相应实型为
float
,则另一个操作数将在不更改类型域的情况下转换为其相应实型为float
的类型。 62 )- 否则,对两个操作数执行整数提升。然后,将以下规则应用于提升后的操作数:
- 如果两个操作数具有相同的类型,则无需进一步转换。
- 否则,如果两个操作数都具有符号整数类型或都具有无符号整数类型,则将具有较小整数转换等级的操作数转换为具有较高等级的操作数的类型。
- 否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数的类型的秩,则具有符号整数类型的操作数将转换为具有无符号整数类型的操作数的类型。 / li>
- 否则,如果带符号整数类型的操作数的类型可以表示带无符号整数类型的操作数的所有值,则将带无符号整数类型的操作数转换为带符号整数的操作数的类型类型。
- 否则,两个操作数都将转换为与带符号整数类型的操作数类型相对应的无符号整数类型。
有关“整数促销”的更多信息,请参见§6.3.1 Arithmetic operands和§6.3.1.1 Boolean, characters, and integers。
在可以使用
int
或unsigned int
的表达式中可以使用以下内容:
- 具有整数类型(
int
或unsigned int
以外的整数类型的对象或表达式)的整数转换等级小于或等于int
和unsigned int
的等级。_Bool
,int
,signed int
或unsigned int
类型的位域。如果
int
可以表示原始类型的所有值(受位字段的宽度限制),则该值将转换为int
;否则,它将转换为unsigned int
。这些被称为整数促销。 58)所有其他类型都被整数促销保持不变。
“等级”一词在该部分中定义;这很复杂,但是基本上long
的排名高于int
,而int
的排名高于char
。
毫无疑问,这些规则在C ++中略有不同,但是最终结果基本上是相同的。
答案 1 :(得分:5)
在算术中,比int
窄的整数被提升为int
,然后对它们进行算术以int
类型进行。如果将结果存储为uint8_t
或其他类型,则它将转换为该类型。但是,如果将其传递给printf
,它将保留为int
。
在C中,用于实数的常规算术转换为:
long double
,则另一种将转换为long double
。double
,则另一个将转换为double
。float
,则另一个将转换为float
。整数促销为:
unsigned int
宽 1 ,则不会更改。int
可以表示该类型的所有值,则该值将转换为int
。unsigned int
。1 C标准实际上使用了 rank 的技术分类,其中涉及更多详细信息。它会影响C实现,在这种实现中,除了仅带符号和无符号之外,多个整数类型可以具有相同的宽度。