【问题标题】:Printing a C Pointer as %i and %u将 C 指针打印为 %i 和 %u
【发布时间】:2017-06-14 16:04:27
【问题描述】:

背景:老牌程序员,重温 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 为底的数字,那么最直接的方法是什么?

【问题讨论】:

  • 你得到 0x50835878 因为这是 0x7fff50835878 的低 4 个字节
  • 谢谢@ChrisTurner -- 你和 chux 在下面的 cmets 让我意识到假设指针地址适合 int 是多么令人费解!
  • @AlanStorm,您的输出和讨论中的地址不匹配。也许不同的运行。请先解决这个问题。造成如此多的混乱。
  • @AjayBrahmakshatriya D'oh!对于那个很抱歉。我认为它是固定的。从多次运行中复制/粘贴。

标签: c pointers casting hex


【解决方案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); 

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

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

...将指针的十六进制地址表示为以 10 为底的数字,最直接的方法是什么?

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


【讨论】:

  • “将 int* 转换为 void* 不会丢失引用数据所需的信息。” - 这不完全正确。 void * 中的信息可能较少。只有与相同类型的转换才能保证比较相等。这并不意味着void * 中没有丢失任何信息(至少原始类型信息总是丢失)。并且将指针转换为interer 是实现定义的。不能保证它会被截断。
  • @chux 感谢您的关注和帮助。回复:uintptr_t 类型——这是标准 C 系统的一部分吗?在某个图书馆?当我尝试使用它时,我收到了use of undeclared identifier 'uintptr_t' 警告。
  • @AlanStorm 在&lt;stdint.h&gt; 中寻找uintptr_t。 C11 和 C99 可能包括它。它是一个 optional 整数类型,但很可能已定义。它是 C 标准的一部分。如果找不到,请转换为 unsigned long long"%llx"
  • 谢谢@chux,stdint.h 做到了(虽然inttypes.h 也做到了,¯_(ツ)_/¯)另外,对于其他任何人,我会继续为了完整起见,我最终使用@chux 的答案的格式。
  • @AlanStorm 最好发布您自己的答案或附加到您的帖子中,而不是更改此答案。建议回滚编辑。顺便说一句:%lx\n" ,(uintptr_t) 不一定匹配。
【解决方案2】:

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

#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 上的转换器非常有用

【讨论】:

  • uintptr_t 可能与unsigned long 的类型不同,因此printf("pointerInteger as %%lu = %lu\n" ,(uintptr_t)pointerInteger); 可能需要在其他平台上工作。
  • 您需要"%" PRIuPTR 以便携方式打印uintptr_t,而不是"%lu"。您需要 #include &lt;inttypes.h&gt; 来获取所有 PRI/SCN 宏。
猜你喜欢
  • 1970-01-01
  • 2011-01-29
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
相关资源
最近更新 更多