【问题标题】:When printing a memory address of a variable using printf, why do %x and %p return different yet similar values?使用 printf 打印变量的内存地址时,为什么 %x 和 %p 返回不同但相似的值?
【发布时间】:2017-10-27 17:43:49
【问题描述】:

我正在尝试打印变量(特别是 argc)的内存地址。我正在使用 printf 并且我知道 %x 返回一个无符号十六进制整数,而 %p 返回一个指针地址。下面是我的简单代码供参考

int main (int argc, char **argv) {
  printf("argc: addr=%x addrp=%p val=%x\n",&argc,&argc,argc);
  return 0;
}

这样跑:./a.out 这是

它输出:argc: addr=af5144cc addrp=0x7ffcaf5144cc val=3

我看到 %x 返回一个字节的地址,对吗?因为它有 8 个数字或位?

但是,%p 返回相同的字节,前面有更多信息。什么是“0x7ffc”部分,它是什么意思?它是内存地址的一部分还是指出某种类型的信息?我知道 0x 部分意味着它是一个十六进制数。 %x 或 %p 是真正的内存地址吗?谢谢!

【问题讨论】:

  • %x 打印指针是未定义的行为。用任何东西打印非void 指针是未定义的行为
  • %x 打印一个unsigned int,在大多数现代平台上,它是 32 位的。 %p 打印特定于平台的指针值。有些平台是 32 位的,有些是 64 位的,可能还有其他大小。
  • 您的unsigned 有32 位,但指针有64 位,所以%x 正在截断地址。

标签: c


【解决方案1】:

%x 打印一个unsigned int,在大多数现代平台上,它是 32 位的。

%p 打印特定于平台的指针值。
有些平台是 32 位的,有些是 64 位的(可能还有其他大小)

sizeof(unsigned int)往往等于sizeof(void*),但完全不能保证,常见的是32位unsigned int和64位void*

因此,%x%p 打印的宽度不同。

【讨论】:

  • 不提这些都是未定义的行为这个答案是不完整的。
  • 谢谢。所以 %p 返回一个更大的值,因为我有一个 64 位操作系统?
  • 大小相关性无关紧要。这是简单的 UB,因为“如果任何参数不是相应转换规范的正确类型,则行为未定义。”
【解决方案2】:

代码正在调用未定义的行为C Standard 中的 fprintf 规范声明(重点是我的):

对于%x

o,u,x,X
-- unsigned int 参数转换为无符号八进制 (o)、无符号十进制 (u) 或 dddd 样式中的无符号十六进制表示法(x 或 X);

对于%p

p
参数应该是一个指向无效的指针。指针的值为 转换为一系列打印字符,在 实现定义的方式。

然后here:

如果任何参数不是对应的正确类型 转换规范,行为未定义

您为这两个说明符提供了一个非空指针,这绝对不是转换规范的正确类型。

更新

正如@chux 所建议的,完全合规的调用将如下所示:

printf("argc: addr=%x addrp=%p val=%x\n", 
    (unsigned)(uintptr_t)(void*) &argc, (void*)&argc, (unsigned)argc);

【讨论】:

  • 建议添加一个合规的printf()。也许printf("argc: addr=%x addrp=%p val=%x\n", (unsigned) &argc, (void*)&argc, (unsigned)argc);
  • @chux 我认为(unsigned) &argc 也是UB?
  • (unsigned) &argc 是 OK “任何指针类型都可以转换为整数类型。” §6.3.2.3 6 除非“如果结果不能以整数类型表示,则行为未定义。”所以也许(unsigned) (uintptr_t) (void*)&argc
  • @chux 啊,好的。我读这两个句子好像有一个例外,一些指针不能表示为整数类型。现在我发现我看错了。
【解决方案3】:

因为指针不是整数。

指针是指针。打印指针的正确方法是使用%p

你可能认为你知道指针只是整数。 (过去,指针只是整数。)如果你知道你在做什么,你仍然可以把指针当作整数来处理,但你必须知道你在做什么.

例如,您必须知道指针的实际大小。它们的大小可能与普通的 int 不同,尤其是在所谓的 64 位平台上时。

因此,如果%x 不起作用,您也许可以使用%lx%llx 逃脱。但是,大多数时候,使用%p 会更容易(也更便携)。

【讨论】:

    猜你喜欢
    • 2022-11-23
    • 2021-04-01
    • 2016-12-18
    • 1970-01-01
    • 2012-03-13
    • 1970-01-01
    • 2016-12-11
    • 1970-01-01
    • 2021-12-02
    相关资源
    最近更新 更多