【问题标题】:integer promotion in cc中的整数提升
【发布时间】:2018-02-27 08:07:42
【问题描述】:

假设我有一台 32 位机器。

我知道在整数提升期间,表达式被转换为:

  • int如果原始类型的所有值都可以用 int 表示
  • unsigned 否则

你能解释一下下面的表达式会发生什么吗?总的来说,这里的排名是如何运作的?

第一个sn-p:

int16_t  x, pt;
int32_t  speed;
uint16_t length;
x = (speed*pt)/length;

第二个:

x = pt + length;

#编辑:

我发现以下链接非常清楚地描述了该问题: Implicit type conversion.

具体看Lundin的回答,很有帮助!

【问题讨论】:

  • si16si32u16 是什么?
  • 在不知道sizeof(int) 相对于sizeof(si16) 和其他人的情况下,问题是不可能的答案。
  • "假设我有 32 位机器。"根本不相关。我们需要知道您的int 的详细信息。
  • @David Bowling ,si16 表示有符号短(大小 16 位),si32 位表示有符号整数(大小 32 位),u16 表示无符号短(大小 16)
  • 为什么是si16 而不是u16,而不是ui16

标签: c integer-overflow integer-promotion


【解决方案1】:

整数提升规则,正确引用 C11 6.3.1.1:

如果int 可以表示原始类型的所有值(受限制 通过宽度,对于位域),值被转换为int; 否则,它将转换为unsigned int。这些被称为 整数促销。所有其他类型都不变整数 促销活动。

“否则,将其转换为无符号整数”实际上仅用于一种特定的特殊情况,即较小的整数类型unsigned shortunsigned int 具有相同的大小。在这种情况下,它将保持未签名状态。

除了这种特殊情况,所有小整数类型总是被提升为(有符号)int,无论它们的符号是什么。


假设 32 位 int,则:

 x = (speed*pt)/length;

speed 签名为 32,不会被提升。 pt 将整数提升为 int(有符号 32)。 speed*pt 的结果类型为 int

length 将整数提升为int。除法将使用int 类型的操作数进行,结果类型将为int

当分配给x时,结果将被转换为带符号的16(分配期间的左值转换)。

x = pt + length; 类似,这里 + 的两个操作数在加法之前都会被提升为int,然后结果将被转换为有符号的 16。

详情见Implicit type promotion rules

【讨论】:

  • 能否请您解释一下:“所有其他类型都不会因整数促销而改变。”
  • @Monir 有了更多上下文,这意味着所有不属于“小整数类型”的类型都不受规则影响。小整数类型有:bool、char、short(以及它们的 stdint.h 等价物)。
  • 如果你能证明它不会溢出,则允许在不先将其转换为 int 的情况下应用运算符。
  • @alinsoar 编译器可以优化此类表达式,但它们确实不允许优化由提升引起的副作用,包括符号的隐式更改。
【解决方案2】:

整数提升规则在6.3.1.8 Usual arithmetic conversions中定义。

1.  int16_t  x, pt;
    int32_t  speed;
    uint16_t length;
    x = (speed*pt)/length;

2. x =  pt + length;

排名实际上意味着来自limits.h 中CAM 定义的类型的位数。标准对CAM中的低位类型进行了规定,以对应实施中的低位类型。

对于您的代码,

speed * pt

是int32_t和int16_t之间的乘法,也就是说,它被转化为

speed * (int16_t => int32_t) pt

结果tmp1 将是int32_t

接下来会继续

tmp1_int32 / length

长度将从uint16_t 转换为int32_t,所以它会计算tmp2 所以:

tmp1_int32 / (uint16_t => int32_t) length

结果tmp2 将是int32_t 类型。

接下来它将评估一个赋值表达式,左侧为 16 位,右侧为 32 位,因此它将结果剪切为:

x = (int32_t => int16_t) tmp2_int32

您的第二个案例将被评估为

x = (int32_t => int16_t) ( (int16_t => int32_t) pt + (uint16_t => int32_t) length )

如果一个运算符的两个操作数的秩都小于 int 的秩,CAM 允许在运算不溢出的情况下将这两种类型相加,然后将结果转换为整数。

也就是说,INT16+INT16 都可以在

 INT16+INT16

或在

 (int32_t => int16_t) ((int16_t => int32_t) INT16 + (int16_t => int32_t) INT16)

前提是添加可以不溢出。

【讨论】:

  • “Ranking”,即转化排名,在6.3.1.1中正式规定。
  • “CAM”应该是什么意思?
  • c 抽象机
  • 我说的是关于我的参考的整数促销,而不是排名。
  • 更准确地说,CAM是指标准定义的抽象语义。
猜你喜欢
  • 2018-08-06
  • 1970-01-01
  • 1970-01-01
  • 2017-07-01
  • 2011-05-05
  • 2017-08-21
  • 1970-01-01
  • 2012-10-05
相关资源
最近更新 更多