将指针转换为64位整数,为什么在32位和64位平台上的结果不同

Jim*_*hen 3 c

我有一个像这样的代码片段(up.cpp):

#include <stdio.h>

typedef unsigned long long Uint64;
int main()
{
    void *p = (void*)0xC0001234;
    Uint64 u64 = (Uint64)p;
    printf("{%llx}\n", u64);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

使用32位gcc 4.8.1编译它,我得到输出:

{ffffffffc0001234}
Run Code Online (Sandbox Code Playgroud)

使用64位gcc 4.8.1编译它,我得到输出:

{c0001234}
Run Code Online (Sandbox Code Playgroud)

是的,64位的值为32位.gcc 4.8.1来自openSUSE 13.1.

我也试过它的Visual C++ 2010和x86的64位编译器(有点代码变化,__int64%I64x),以及令人惊讶的得到相同的结果.

当然,我打算{c0001234}同时使用x86和x64.但为什么会有这样的差异呢?

AnT*_*AnT 5

这个行为

Uint64 u64 = (Uint64)p;
Run Code Online (Sandbox Code Playgroud)

不是由语言定义的.它是实现定义的.

虽然64位平台可能会将其实现为纯概念转换(指针"填充"整个目标值),但在32位平台上,实现面临两难:如何将32位指针值扩展为64-位整数值,带符号扩展或不带?显然,您的实现决定签署扩展价值.

显然,您的实现认为在指向无符号转换时,原始指针值应该作为排序的有符号值.不过,这将是一个相当奇怪的决定.我不能在GCC中重现它:http://coliru.stacked-crooked.com/a/9089ccda625bd65d

如果您的平台上发生了这种情况,那么您应该能够通过转换为uintptr_t第一个(作为中间类型)来抑制此行为,如评论中的@barak manos所示.