20

我正在将一些 32 位兼容代码转换为 64 位 - 我遇到了障碍。我正在编译一个 VS2008 x64 项目,我收到以下警告:

warning C4334: '<<' : result of 32-bit shift implicitly converted to 64 bits
(was 64-bit shift intended?)

这是原始代码行:

if ((j & (1 << k)) != 0) {

如果我遵循微软的建议,这就是它的样子:

if ((j & (1i64 << k)) != 0) {

当代码将在 32 位和 64 位系统上编译时,这样做安全吗?如果是这样,请解释为什么我必须在末尾添加“i64”,以及为什么这不会影响 32 位编译。否则,将不胜感激。

除此之外,我还有一些看起来更棘手的代码。

if (id[j] != id[j ^ (1u << k)]) {

我知道“u”表示该数字是无符号的,但是在不超过有符号最大值的值上指定它有什么意义......我猜这与位移有关?

4

4 回答 4

11

1具有int符合 C++ 标准的类型。在 64 位 Microsoft 编译器int上有 sizeof = 4 字节,这意味着它int是 32 位变量。1i64有类型__int64

当您使用移位运算符时,结果的类型与左操作数的类型相同。这意味着移位1您将获得 32 位结果。Microsoft 编译器假定它可能不是您所期望的(在 64 位平台上)并给您警告消息。

当您1i64在两个平台上使用时,结果将是 64 位。j并将0被隐式转换为 64 位。所以整个表达式将在 64 位变量中计算,结果将是bool.

因此1i64,在两个 (32/64) 平台上使用都是安全的。

于 2009-08-12T05:22:59.043 回答
4

i64后缀是 Microsoft 特定的。为了更便携(如果您担心的话),您可以使用INT64_C()来自的宏stdint.h

#include <stdint.h>

// ...

if ((j & (INT64_C( 1) << k)) != 0) { ... }

不幸的是,MS 没有将stdint.h其作为其 C 库的一部分(大多数其他编译器似乎都有),但幸运的是,您可以从多个来源获得一个:

现在,您将拥有一个 64 位常量,可以与各种编译器一起使用。

至于为什么您可能需要或需要 64 位值,这取决于表达式各个部分的类型。了解 , 的类型idj能够k回答是否需要u常量上的 ' ' 后缀以及它可能产生的影响会很有帮助。

于 2009-08-12T06:40:24.020 回答
1

1i64 我相信应该是一个有符号的 64 位整数。我不能宣称在 Microsoft 的实现方面有任何专长,但在 GCC 中,在 32 位 CPU 上支持 64 位整数的解决方案是使用结构和各种黑魔法宏来制作 long longs 双字。因此,i64应该是兼容的。

至于 voodoo 的最后一位 - 指定 1u 的唯一一点是因为如果 k 足够大,移位的结果可能会满足/超过 32 位存储,在这种情况下,结果会有所不同如果 LH 操作数被视为有符号或无符号整数。

于 2009-08-12T04:08:08.073 回答
0

由于该代码将 64 位变量j与移位的(32 位)结果进行“与”运算,因此编译器会将结果“扩展”为 64 位。

您可能希望控制“and”的第二个操作数的计算方式,因此编译器建议您通过将第一个操作数设为__int64. 这在 32 位中是安全的,但您实际上应该查看类型j以决定运算符是 32 位还是 64 位。

这在第二位尤其重要,其中结果用作索引。

于 2009-08-12T05:42:46.807 回答