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
不会,因为后者会使用无符号算术。与往常一样,编译器可以定义超出标准要求的行为。
在我的代码中,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 anint
; otherwise, it is converted to anunsigned 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
不会,因为后者会使用无符号算术。与往常一样,编译器可以定义超出标准要求的行为。