为什么在 C 和 C + + 中的算术运算之前必须将 short 转换为 int?

从我从 这个问题得到的答案来看,似乎 C + + 在从 C 执行算术运算时继承了将 short转换为 int的这一要求。我可以向你们介绍一下当初在 C 中引入的 为什么吗?为什么不像 short那样做这些操作呢?

例如(摘自 dyp 在评论中的建议) :

short s = 1, t = 2 ;
auto  x = s + t ;

x将具有 Int的类型。

11985 次浏览

它不是语言的一个特性,而是运行代码的物理处理器体系结构的一个限制。C 语言中的 int打字机通常是标准 CPU 寄存器的大小。更多的硅占用更多的空间和更多的功耗,因此在许多情况下,算术只能在“自然大小”的数据类型上进行。这并不是普遍正确的,但是大多数体系结构仍然有这个限制。换句话说,当添加两个8位数时,实际上在处理器中进行的是某种类型的32位算术,然后是一个简单的位掩码或另一个适当的类型转换。

这个相关的问题似乎很好地解释了这个问题: CPU 就是不能。32位 CPU 有为32位寄存器设置的本机算术操作。处理器倾向于使用它喜欢的大小,对于这样的操作,将一个小值复制到本机大小的寄存器是便宜的。(对于 x86架构,32位寄存器的命名就好像它们是16位寄存器的扩展版本(eaxaxebxbx等) ; 参见 X86整数指令)。

对于一些非常常见的操作,特别是向量/浮点运算,可能有专门的指令在不同的寄存器类型或大小上进行操作。对于一个短的东西,填充(最多)16比特的零只有很少的性能成本,并且添加专门的指令可能不值得在骰子上花费时间或空间(如果你真的想知道为什么; 我不确定它们会占用实际的空间,但它确实变得更加复杂)。

shortchar类型被认为是标准的“存储类型”,即子范围,你可以用来节省一些空间,但不会买你任何速度,因为他们的大小是“非自然”的 CPU。

在某些 CPU 上,这是不正确的,但是好的编译器足够聪明,能够注意到,如果你向一个无符号字符添加一个常量,然后将结果存储回一个无符号字符,那么就没有必要进行 unsigned char -> int转换。 例如,使用 g + + 为

void incbuf(unsigned char *buf, int size) {
for (int i=0; i<size; i++) {
buf[i] = buf[i] + 1;
}
}

是正义的

.L3:
addb    $1, (%rdi,%rax)
addq    $1, %rax
cmpl    %eax, %esi
jg  .L3
.L1:

其中可以看到使用了无符号字符加法指令(addb)。

如果在 short int 之间进行计算并将结果存储在 short int 中,也会发生同样的情况。

如果我们看看 6.3.1.8 常用的算术转换节中的 国际标准ーー程序设计语言ーー C,它说(强调我的未来) :

标准中对这些转换的规则比较简单 在 K & R 的修改: 修改适应增加的 类型和值保留规则。 < strong > 添加了显式许可 以超过绝对需要的“宽”类型进行计算, 因为这有时可以产生更小更快的代码,而不是 经常提到正确的答案。计算也可以是 在“较窄”的类型中执行的,只要是同样的规则 显式强制转换总是可以用来获得 所需类型的值

C99标准草案的6.3.1.8 部分涵盖了应用于算术表达式的操作数的 常用的算术转换,例如 6.5.6加法运算符部分说:

如果两个操作数都有算术类型,则使用 < strong > 通常的算术 对它们执行转换

我们在 6.5.5乘法运算符部分也找到了类似的文本。在 太短了操作数的情况下,首先从 6.3.1.1布尔值、字符和整数节应用 整数提升,它说:

如果 int 可以表示原始类型的所有值,则该值为 转换为整型; 否则,转换为无符号整型。 这些被称为整数促销 . 48)所有其他类型都是 整数提升没有改变。

关于 整数提升基本原理或国际标准ーー程序设计语言ーー C6.3.1.1部分的讨论实际上更有趣,我将有选择地引用 b/c,它太长了,不能完全引用:

实现属于 两大阵营,可以对其进行描述 作为 无符号保持和值保持

[...]

无符号保留法无符号保留法呼吁促进两个较小的 这是一个简单的规则,并且产生一个 独立于执行环境的类型。

保值方法保值方法呼吁将这些类型推广到 如果该类型可以正确地表示 原始类型,否则将这些类型提升为无符号 因此,如果执行环境将 short 表示为 something 小于 int 的 unsignedshort 变为 int; 否则变为 无符号整数。

在某些情况下,这可能会产生一些意想不到的结果,正如 无符号类型和大符号类型之间隐式转换的不一致行为所展示的那样,还有很多类似的例子。尽管在大多数情况下,这会导致操作按预期工作。