【问题标题】:using %x to print the hex address contained in a pointer使用 %x 打印指针中包含的十六进制地址
【发布时间】:2014-08-08 19:35:05
【问题描述】:

我刚刚阅读了这篇简短的文章http://karwin.blogspot.com/2012/11/c-pointers-explained-really.html,它很好地描述了指针。然而,作者说地址只是这些十六进制值,所以他用 %x 打印它,但是当我这样做时,我不仅会从编译器收到警告说我传递的是指针而不是无符号整数,而且有时我得到的东西根本不像地址(比如 1C)。有人可以澄清一下这个问题吗?

【问题讨论】:

  • 使用 %p 作为指针
  • 我继续对帖子发表评论:P
  • @DrewMcGowen 实际上,指针也可以更小,以产生不同的灾难性影响。此外,无论您以何种方式对编译器撒谎,它都是 UB。

标签: c pointers memory-address


【解决方案1】:

%x 期望其对应的参数具有unsigned int 类型,这就是您得到警告和时髦输出的原因。使用%p显示指针值:

T *p = some_pointer_value;
...
printf( "p = %p\n", (void *) p );

%p 期望其对应参数的类型为void *。这几乎是您应该在 C 中显式转换指向 void * 的指针的唯一地方。

编辑

刚刚看了一页。请注意,该代码示例是(写于 1990 年左右),并且到处使用 K&R 风格(1989 年之前的标准)函数定义语法和隐式 int。它使用 %x 来显示指针值,因为 %p 转换说明符直到 1989 年标准才添加到语言中。

它应该被用作现代 C 编程实践的模型。

不过,他对指针的解释相当不错。

【讨论】:

  • 那么 %x 不需要 unsigned int 吗?如果确实如此,那么我的问题仍然存在:他为什么会得到 0x 类型的输出......这看起来确实像一个地址,如果不是完全错误的值,我只会得到地址的一小部分。
  • @user96454: 如果类型不是转换说明符所期望的,那么行为是 undefined;确切的输出会有所不同。
【解决方案2】:

%x 用于打印十六进制值。虽然指针通常以十六进制编写,但对于使 %x 不合适的指针还有其他注意事项,例如您看到的 1C 输出。

%p 用于指针,可能是您正在寻找的。它将更好地格式化指针,因为它知道它是一个指针。

1C 是一个完全有效的十六进制输出,但是对于指针来说这很奇怪,因为您希望在显示指针时会发生某些特殊的事情,例如具有正确的长度。

由于%x 用于十六进制数字,将指针传递给它会给你一个警告。它给你警告的一个原因是指针不一定与 unsigned int 大小相同。

【讨论】:

  • %x 用于以十六进制打印unsigned int 值;传递其他任何东西都会导致未定义的行为。将%x 与指针一起使用不会必然 产生警告,尽管一些编译器(例如gcc)会在可能时尝试发出警告。 (这并不总是可能的,因为格式字符串不必是字符串文字。)
  • %p 并不适用于所有指针,仅适用于 void* 类型的指针。只有数据指针可以转换为它,除非实现保证它(甚至在标准中提到的一个非常常见的扩展)。
【解决方案3】:

%x 需要 unsigned int,传递其他任何内容都是 UB

对于打印数据指针,有%p 可以打印空指针(类型为void*,转换是 可选的),通常会以十六进制表示法打印。

如果您对此不满意,请考虑将指针转换为 uintptr_t 并使用来自 <inttypes.h> 的格式说明符宏 PRIxPTRPRIXPTR 打印,以保证十六进制输出。
您甚至可以选择使用的案例。

【讨论】:

  • 要打印指针值,请使用%p 并将值转换为void*%pvoid* 定义。无法保证其他指针类型(char* 和朋友除外)甚至具有相同的大小或表示形式。
  • @KeithThompson:补充说需要转换,谢谢提醒。
【解决方案4】:

如果使用 %x 或 %u 等整数格式操作指针,则会给出未定义的结果。建议将 %p 用于指针。 就警告而言,%x 需要一个 unsigned int,并且您的变量的大小或对齐要求可能与 unsigned int 不同,因此您会收到警告。

【讨论】:

    【解决方案5】:

    值不能是“十六进制”。价值观只是价值观。同时,“十六进制”是一种表示人类消费价值的方式。 “十六进制”是一个符号。

    直接在指针上使用%x 是非法的,因为%x 格式说明符需要unsigned int 参数,而不是指针。可以将指针转换为unsigned int 类型,并且结果可以与%x 格式说明符一起使用,但这在一般情况下不起作用,因为unsigned int 类型很容易太窄而无法正确表示数字地址值。

    换句话说,忘记%x。它在那个应用程序中毫无用处。你文章的作者做错了。

    如果你真的想通过转换为整数类型来打印指针p,正确的方法是这样

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

    注意uintptr_t 类型和PRIxPTR 宏的使用,它代表与该类型关联的实现定义的格式说明符。

    除此之外,您还可以使用专用格式说明符 %p,它会打印 void * 指针,并且通常为此使用十六进制表示法。

    【讨论】:

    • 这是有道理的,但我的指针是 int *,所以如果我们考虑字节大小,unsigned int 类型就足够了吗?那么,在这种特殊情况下,如果 %x 和 %p 都应该输出一个十六进制值,为什么我会得到这些不同的输出
    • @user96454:我看不出它与您的指针类型有什么关系。您的指针是 int * 的事实没有任何区别。在典型的实现中,所有指针都以相同的方式表示。这意味着unsigned int 最终可能不够宽,无法表示指针,任何指针。
    • 您在%x%p 之间的输出中看到了什么区别?如果%p 给你更长的输出,这意味着你的指针对于unsigned int 来说确实太大了,这就是为什么你从%x 得到不同(截断)的输出。
    猜你喜欢
    • 2018-10-20
    • 2013-01-11
    • 1970-01-01
    • 1970-01-01
    • 2014-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-04
    相关资源
    最近更新 更多