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

时间:2014-07-30 14:43:14

标签: 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;
}

人们期望输出是什么?使用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

使用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

当直接从指针转换为无符号long long时,GCC似乎用1&#39;而不是0&#填充了最高有效位。这是GCC中的错误吗?

1 个答案:

答案 0 :(得分:7)

这是根据draft C99 standard部分6.3.2.3 指针定义的实现,其中包含:

  

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

gcc记录了实施here

  

将指针转换为整数的结果,反之亦然(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 ) ;