【问题标题】:Why does uint8_t + uint8_t results in an int? [duplicate]为什么 uint8_t + uint8_t 会产生 int? [复制]
【发布时间】:2017-01-11 13:13:54
【问题描述】:

我注意到对于 8 位变量的简单操作,在操作完成之前将变量转换为 32 位 ints,然后再转换回 8 位变量。

作为一个例子,这个 c++ 程序:

#include <iostream>
#include <cstdint>

int main( void )
{
  uint8_t a = 1;
  uint8_t b = 2;

  std::cout << "sizeof(a)   = " << sizeof( a ) << std::endl;
  std::cout << "sizeof(b)   = " << sizeof( b ) << std::endl;
  std::cout << "sizeof(a+b) = " << sizeof( a+b ) << std::endl;

  return 0;
}

产生以下输出:

sizeof(a)   = 1
sizeof(b)   = 1
sizeof(a+b) = 4

所以我们可以理解发生了什么:

uint8_t c = (uint8_t)((int)(a) + (int)(b));

显然,它似乎在this论坛中所说的C规范中。

另外,在 Visual Studio 2013 中,编写

auto c = a + b; 

将鼠标指针悬停在c 上表示类型为int

问题是:

  • 为什么需要转换,为什么在规范中? (如果可能的话,如果有答案,我希望通过外部信息来源阅读更多关于该主题的信息(例如 MSDN、cppreference)。)
  • 这对性能有何影响?

【问题讨论】:

    标签: c++ types


    【解决方案1】:

    这是由于integral promotion 规则。具体

    小整数类型(如char)的纯右值可以转换为较大整数类型(如int)的纯右值。 特别是,算术运算符不接受小于 int 的类型作为参数,并且在左值到右值转换后自动应用整数提升(如果适用)。这种转换始终保留价值。

    【讨论】:

    • “为什么需要转换,为什么在规范中?”
    • 想象一下你在没有提升的情况下做uint8_t a=200, b=100, c=2; uint8_t d=(a+b)/c;,中间结果会溢出——提升后一切都以适合目标的 150 结束。
    • @JesperJuhl "..如果没有提升,中间结果会溢出" - int a = INT_MAX, b = 343232; int c = a + b 仍然会溢出......所以呢?
    【解决方案2】:

    问题是:

    • 为什么需要转换,为什么在规范中? (如果可能的话,有了答案,我希望外部信息来源阅读更多 关于主题(如 MSDN、cppreference)。)
    • 这对性能有何影响?

    嗯,

    • C++算术运算符取整型操作数的要求可以参考here

    • 积分促销的规则可以在here找到。

    至于为什么它在规范中。假设...虽然 CPU 可能具有可以对 8 位整数进行操作的指令,但在 CPU 内,写入/读取小于寄存器宽度的整数可能涉及您不知道的屏蔽。

    假设您有一个 32 位的寄存器宽度。添加两个 8 位整数通常需要一些掩码来获取 8 位部分并用零填充剩余的 24 位...... ALU 将对寄存器中的数据进行处理并将结果存储在完整的寄存器写入(32 位)中。然后另一个掩码将结果检索为 8 位整数,如果您回退..

    所以推广它不需要任何成本,因为无论如何 CPU 都会这样做。

    请参阅:On 32-bit CPUs, is an 'integer' type more efficient than a 'short' type?

    即使是你的regular 32bit operations on 64bits

    【讨论】:

      猜你喜欢
      • 2015-12-11
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-12
      相关资源
      最近更新 更多