将C指针打印为%i和%u

时间:2017-06-14 16:04:27

标签: c pointers casting hex

背景:成熟的程序员,重新访问C,除了更好地了解幕后真实情况之外,不是为了任何特定目的。

考虑这个程序。

#include <stdio.h>

int main()
{
    //https://stackoverflow.com/questions/2581769/dereference-a-pointer-inside-a-structure-pointer

    int concreteInteger = 42;
    int* pointerInteger;
    pointerInteger = &concreteInteger;

    printf("concreteInteger as %%i = %i\n",concreteInteger);
    printf("pointerInteger  as %%p = %p\n" ,(void*)pointerInteger);        
    printf("pointerInteger  as %%u = %u\n" ,(unsigned)pointerInteger);                
    printf("*pointerInteger as %%i = %i\n",*pointerInteger);
    printf("Done\n");
    return 0;
}

当我在OS X 10.11上编译并运行该程序时,我得到以下输出。

$ cc main.c;./a.out 
concreteInteger as %i = 42
pointerInteger  as %p = 0x7fff5d614878
pointerInteger  as %u = 1566656632
*pointerInteger as %i = 42
Done 

1566656632来自哪里?如果我convert 1566656632 to hex我得到0x5D614878,而不是0x7fff5d614878

那么1566656632来自哪里?我上面做了什么错误的假设?是否将指针作为无符号数字投射在C中未定义的内容?如果是这样,对于奖励积分,如果我想将指针的十六进制地址表示为基数10中的数字,那么最直接的方法是什么?

2 个答案:

答案 0 :(得分:1)

int*转换为void*并不会丢失所需的信息来引用数据,因为转换回int*可以引用concreteInteger

将OP int*转换为unsigned(32位)仅保留指针地址的32位。

首先尝试%x并转换为uintptr_t uintptr_t位于C99中,是可选类型,但非常常见。

 #include <stdint.h>
 ...
 printf("pointerInteger  as %%x = %x\n" ,(unsigned)(uintptr_t) pointerInteger); 

我期待以下,指针的低32位。 @Chris Turner

pointerInteger  as %x = 51af8878

尝试%llx并首先转换为uintptr_t以查看更多内容。

 printf("pointerInteger  as %%llx = %llx\n", 
    (unsigned long long)(uintptr_t) pointerInteger); 

使用<inttypes.h>中的宏,可以使用匹配的打印说明符直接打印uintptr_t类型。

 printf("pointerInteger  %" PRIxPTR "\n", (uintptr_t) pointerInteger); 
  

...将指针的十六进制地址表示为基数10中的数字,这是最直接的方法吗?

指针的地址不是&#34; hex&#34;,它是什么。要显示十进制/十六进制/八进制的指针,请转换为足够宽的整数并使用匹配的打印说明符进行打印。要以便携式打印,请转换为void*并使用"%p",它可以以十六进制打印。

答案 1 :(得分:0)

我将上面的答案标记为最佳,因为它让我得到了我需要的地方,但是下面的程序给了我想要/需要的东西。

#include <stdio.h>
#include <stdint.h>

//needed for the PRI*PTR Macros
#include <inttypes.h>

int main()
{
    //#include <inttypes.h>    
    int concreteInteger = 42;
    int* pointerInteger;
    pointerInteger = &concreteInteger;

    printf("concreteInteger as %%i = %i\n",concreteInteger);
    printf("pointerInteger  as %%p = %p\n" ,(void*)pointerInteger);        
    printf("pointerInteger  as %%u = %u\n" ,(unsigned)pointerInteger);                
    printf("*pointerInteger as %%i = %i\n",*pointerInteger);

    //as base 10 printf
    printf("pointerInteger  as %%lu = %lu\n" ,(uintptr_t)pointerInteger);                    
    printf("pointerInteger  as %%llu = %llu\n" ,(unsigned long long)(uintptr_t)pointerInteger);                    

    //as hex printf
    printf("pointerInteger  as %%lx = %lx\n" ,(uintptr_t)pointerInteger);           
    printf("pointerInteger  as %%llx = %llx\n" ,(unsigned long long)pointerInteger);           

    //using macros from inttypes.h
    printf("pointerInteger  as %%PRIxPTR = %" PRIxPTR "\n", (uintptr_t) pointerInteger);         
    printf("pointerInteger  as %%PRIxPTR = %" PRIdPTR "\n", (uintptr_t) pointerInteger);         

    // 140,734,665,721,976

    printf("Done\n");
    return 0;
}

要带走的几件关键事项。

  1. 我需要stdint.h库来获取(uintptr_t)类型。
  2. 编译器警告让我知道%lu%lx是显示(uintptr_t)的格式字符串
  3. 上面的@chux,将指针转换为(unsigned long long)所需的%llu%llx
  4. binaryhexconverter.com上的转换器非常有用