具有不同宽度变量和铸造的数学

Math with different width variables and casting

考虑以下代码片段:

// The assigned numbers are random and not relevant
uint16_t val = 2;
uint32_t sum = 4;

sum += val; // point 1

sum /= val; // point 2
  1. 在这个操作中,val是否自动转换为uint32_t?如果不是,什么更快 - 铸造它或离开 uint16_t?
  2. 在这个操作中,val是否自动转换为uint32_t?如果不是,什么更快 - 铸造它或离开 uint16_t?

假设架构是 16 位。

在这两种情况下,val 的值都会自动转换为较大的类型 uint32_t。精确的行为取决于 int.

的实际大小
  • 如果类型int有15个值位,则val转换为uint32_t,保留值,加法和除法使用uint32_t 算术,对 232 进行模运算,结果存储在 sum.

  • 如果类型 int 具有 16 到 31 个值位,val 首先提升为 int,保留其值,然后转换提升的值到 uint32_t,再次保留该值,因为它是正数,并且操作如上所述完成。

  • 如果类型 int 有超过 31 个值位,sumval 都会提升为 int,保留值,加法和除法使用int有符号运算,结果被转换为uint32_t,模232,存储到sum.

对于上面的示例值,结果在所有情况下都是相同的,但对于下面的示例,在 int 将具有 32 个值位的假设体系结构上行为未定义:

uint16_t val = 2;
uint32_t sum = 0xffffffff;

sum += val; // signed arithmetic overflow if type `int` has 33 bits

这些隐式提升和转换不是 cast 操作,您可以添加诸如 sum += (uint32_t)val; 之类的显式强制转换,但行为将完全相同并且不会产生任何影响关于性能。

如果编译器可以在编译时确定 val 的值,它可能会将表达式 sum /= val; 编译为右移或乘法以避免昂贵的除法。将无符号值除以 2 的幂是一种廉价的右移操作,如果该值有符号且可能为负,则必须调整移位。对于其他 non-zero 股息,使用乘以 2k/val 到更大的类型。