从32位地址转换为64位整数会产生意外结果

dlp*_*dlp 6 c gcc type-conversion

鉴于以下计划:

#include <stdio.h>

int main(int argc, char** argv)
{
    int i;
    void* p = &i;

    printf("No cast, using %%p: %p\n",
        p);
    printf("Cast to unsigned long using conversion %%lx: %lx\n",
        (unsigned long) p);
    printf("Cast to unsigned long long using conversion %%llx: %llx\n",
        (unsigned long long) p);
    printf("Cast to unsigned long then unsigned long long using conversion %%llx: %llx\n",
        (unsigned long long) (unsigned long) p);

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

人们期望输出是什么?使用GCC 4.4.7进行编译并运行程序,给出以下输出:

No cast, using %p: 0xbf8aa3d8
Cast to unsigned long using conversion %lx: bf8aa3d8
Cast to unsigned long long using conversion %llx: ffffffffbf8aa3d8
Cast to unsigned long then unsigned long long using conversion %llx: bf8aa3d8
Run Code Online (Sandbox Code Playgroud)

使用clang 3.4版进行编译并运行程序会产生我真正期望的结果:

No cast, using %p: 0xbfa64234
Cast to unsigned long using conversion %lx: bfa64234
Cast to unsigned long long using conversion %llx: bfa64234
Cast to unsigned long then unsigned long long using conversion %llx: bfa64234
Run Code Online (Sandbox Code Playgroud)

当从指针直接转换为无符号长long时,看起来GCC用1而不是0来填充最高有效位.这是GCC中的错误吗?

Sha*_*our 7

这是根据C99标准部分6.3.2.3 Pointers定义的实现,其中指出:

任何指针类型都可以转换为整数类型.除非先前指定,否则结果是实现定义的.如果结果无法以整数类型表示,则行为未定义.结果不必在任何整数类型的值范围内.

gcc文件有执行这里:

将指针转换为整数的结果,反之亦然(C90 6.3.4,C99和C11 6.3.2.3).

  • 如果指针表示大于整数类型,则指向整数的转换会丢弃最高有效位,如果指针表示小于整数类型,则为sign-extends1,否则位不变.

  • 如果指针表示小于整数类型,则从整数到指针的强制转换丢弃最高有效位,如果指针表示大于整数类型,则根据整数类型的符号扩展,否则位不变.

或者你可以使用uinitptr_t假设stdint.h可用,这是一个可以保存指针值的无符号整数:

#include <stdint.h>
#include <inttypes.h>

uintptr_t ip = &i ;

printf("0x%016" PRIxPTR "\n", ip ) ;
Run Code Online (Sandbox Code Playgroud)