【发布时间】:2018-04-26 23:47:24
【问题描述】:
while ((1U << i) < nSize) {
i++;
}
使用1U 代替1 有什么特别的原因吗?
【问题讨论】:
-
这段代码出现在php的源代码中,在文件zend_hash.c中。
while ((1U << i) < nSize) {
i++;
}
使用1U 代替1 有什么特别的原因吗?
【问题讨论】:
在大多数编译器上,两者都会给出具有相同表示的结果。但是,根据 C 规范,对有符号参数进行位移操作的结果会给出实现定义的结果,因此在 theory 中1U << i 比1 << i 更可移植。实际上,您会遇到的所有 C 编译器都将有符号左移视为无符号左移。
另一个原因是如果nSize 是无符号的,那么将它与有符号的1 << i 进行比较将产生编译器警告。将 1 更改为 1U 可以消除警告消息,并且您不必担心如果 i 是 31 或 63 会发生什么。
编译器警告很可能是代码中出现1U 的原因。我建议在打开大多数警告的情况下编译 C,并通过更改代码来消除警告消息。
【讨论】:
1<<i 不是实现定义的。只要值不溢出INT_MAX,它就定义明确,如果溢出(进入符号位)未定义的行为。
1U 未签名。它可以携带两倍大的值,但没有负值。
根据环境,使用 U 时,i 最大可以是 31 或 15,而不会导致溢出。如果不使用 U,i 最多可以是 30 或 14。
31, 30 用于 32 位 int
15, 14 用于 16 位 int
【讨论】:
如果 nSize 是一个int,它最大可以是 2147483647 (2^31-1)。如果您使用1 而不是1U,那么1 << 30 将得到1073741824,1 << 31 将是-2147483648,因此如果nSize 大于1073741824,则while 循环将永远不会结束。
对于1U << i,1U << 31 的计算结果为 2147483648,因此您可以安全地将其用于 nSize 高达 2147483647。如果 nSize 是无符号整数,则循环也可能永远不会结束,就像在这种情况下一样nSize 可以大于1U << 31。
编辑:所以我不同意答案告诉你 nSize 应该是无符号的,但如果它是有符号的,那么它不应该是负数......
【讨论】:
1U 未签名。
他们在表达式中使用无符号值的原因是(我猜)因为nSize 也是无符号的,并且编译器(当使用某些参数调用时)在比较有符号和无符号值时会发出警告。
另一个原因(在我看来不太可能,但如果不知道 nSize 应该假设的 wath 值我们无法知道)是无符号值可能是有符号值的两倍,因此 nSize 可能高达~4*10^9 而不是 ~2*10^9。
【讨论】: