在我的代码中,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
[...]
我本来希望wert1为16位,而i = 15值则为零,顾名思义,它长16位。
这两个变量没有区别。
我在Raspian中找到了uint16_t最大值的一些参考(请参见https://raspberry-projects.com/pi/programming-in-c/memory/variables)
那为什么没有区别?
非常感谢!
答案 0 :(得分:2)
Both operands of <<
will undergo integer promotions,即C11 6.3.11p2:
2在可以使用int或unsigned int的表达式中可以使用以下内容:
- 具有整数类型(int或unsigned int除外)的对象或表达式,其整数转换等级小于或等于int和unsigned int的等级。
- _Bool,int,signed int或unsigned int类型的位字段。
如果
int
可以表示原始类型的所有值(受位字段的宽度限制),则该值将转换为int
;否则,它将转换为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。
但是,如果移位宽度大于或等于操作数的宽度(在这种情况下为32位),会发生仍然(即使在GCC中也是如此)的情况,所以{{1 }}和<< 32
将具有不确定的行为。
除此之外,通常,C标准指出,如果将正号整数左移以使符号位发生变化,则行为是不确定的!当您将<< 33
左移太多位时,就会发生这种情况,它将改变uint16_t
的移位位。因此,
int
在32位平台上具有未定义的行为,因为最高位已移至(uint16_t)0xFFFF << 16
的符号位,而
int
不会,因为后者将使用无符号算术。与往常一样,编译器可以定义超出标准要求的行为。
答案 1 :(得分:1)
没有区别,因为整数促销
您真的应该阅读有关Implicit type promotion rules主题的精彩文章
假设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);