uint16_t 和 uint32_t 之间的差异

Diff between uint16_t and uint32_t

在我的代码中,uint16_t 和 uint32_t 之间没有区别。为什么?

我在带有 ARMv7(32 位)的 RasPi 上使用 Raspbian。

root@zentrale:/src# uname -a
Linux zentrale 4.19.42-v7+ #1219 SMP Tue May 14 21:20:58 BST 2019 armv7l GNU/Linux

这是代码:

void main()
{

        uint16_t wert1;
        uint32_t wert2;

        int i;

        wert1=2;
        wert2=2;
        for (i=0; i<33;i++)
        {
                printf("i: %2d\tLShifted wert1: %10u\t",i,wert1 << i);
                printf("RShifted wert1: %10u\t",wert1 >> i);
                printf("LShifted wert2: %10u\t",wert2 << i);
                printf("RShifted wert2: %10u\n",wert2 >> i);
        }
exit(0);
}

这是剥离后的输出:

i:  0   LShifted wert1:          2      RShifted wert1:          2      LShifted wert2:          2      RShifted wert2:          2
i:  1   LShifted wert1:          4      RShifted wert1:          1      LShifted wert2:          4      RShifted wert2:          1
[...]
i: 14   LShifted wert1:      32768      RShifted wert1:          0      LShifted wert2:      32768      RShifted wert2:          0
i: 15   LShifted wert1:      65536      RShifted wert1:          0      LShifted wert2:      65536      RShifted wert2:          0
i: 16   LShifted wert1:     131072      RShifted wert1:          0      LShifted wert2:     131072      RShifted wert2:          0
[...]

我原以为 16 位的 wert1 会随着 i=15 值变为零,正如名称所示,它是 16 位长。

相反,这两个变量没有区别。

我在 Raspian 中找到了 uint16_t 最大值的一些参考(参见 https://raspberry-projects.com/pi/programming-in-c/memory/variables

那为什么没有区别呢?

非常感谢!

因为 整数促销

没有区别

你真的应该仔细阅读关于这个主题的post

假设4字节int,在进行任何算术运算之前,先将一个uint16_t转换为有符号的int,然后再进行运算。

负数左移未定义。但在这种情况下,这个数字不能为负数。所以你会得到与 uint32_t

相同的输出

您应该对左移的输出进行类型转换以便正确操作。

另外,你是 运行 直到 i<33 的循环。在 i==32,您将对 uint32_t 有未定义的行为,在 i==31,您将对 uint16_t

的有符号整数有未定义的行为
 printf("i: %2d\tLShifted wert1: %10u\t",i,  (uint16_t)(wert1 << i);

Both operands of << will undergo integer promotions, i.e. C11 6.3.11p2:

2 The following may be used in an expression wherever an int or unsigned int may be used:

  • An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.
  • A bit-field of type _Bool, int, signed int, or unsigned int.

If an int can represent all values of the original type (as restricted by the width, for a bit-field), the value is converted to an int; otherwise, it is converted to an unsigned int.

由于 int 在您的平台上是 32 位宽,因此 uint16_t 的所有值都可以用 int 表示。 uint32_t 转换为 unsigned int!

现在他们两个的行为似乎 相等因为 GCC 保证了其中的大部分! GCC 支持的所有体系结构上的所有带符号算术都使用 2 的补码;和 additionally GCC does not consider the behaviour << on signed numbers as undefined in the cases where the sign bit is changed

但是,仍然未定义(即使在 GCC 中)如果移位宽度大于或等于操作数的宽度(在本例中为 32 位),会发生什么情况,因此 << 32<< 33 将具有未定义的行为。

除此之外,一般来说,C 标准规定,如果正符号整数为 left-shifted,则行为未定义,因此符号位会发生变化!当您将 uint16_t 左移很多位以至于它会改变 int 的移位位时,就会发生这种情况。因此,

(uint16_t)0xFFFF << 16

在 32 位平台上有未定义的行为,因为最高位被移到 int 的符号位,而

(uint32_t)0xFFFF << 16

不会,因为后者会使用无符号算术。与往常一样,编译器可以定义超出标准要求的行为。