【问题标题】:difference between printing a memory address using %u and %d in C?在 C 中使用 %u 和 %d 打印内存地址的区别?
【发布时间】:2011-07-09 16:21:17
【问题描述】:

我在读一本 C 书。为了打印出变量的内存地址,本书有时会使用:

printf("%u\n",&n);

有时,作者写道:

printf("%d\n",&n);

结果总是一样的,但我不明白两者之间的区别(我知道 %u 表示无符号)。

谁能详细说明一下?

非常感谢。

【问题讨论】:

  • 我会使用printf("%x\n",&n) 来打印地址的十六进制表示。但这只是我。
  • 扔掉这本书——你永远不应该使用%u%d来打印地址,因为地址可能比int有更多的位——使用%p,或者失败了%#llx
  • 您还应该转换地址以匹配您选择的说明符的类型。 printf 不能进行任何自动转换,因为参数没有原型参数。使用%p 即为(void *),使用%#llx 即为(unsigned long long),等等

标签: c unsigned


【解决方案1】:

%d%u 将在最高有效位未设置时打印相同的结果。然而,这根本不是可移植的代码,也不是很好的风格。我希望你的书比这个例子看起来更好。

【讨论】:

  • 实际上这本书应该告诉他/她使用printf("%p\n",(vid*)&n);
  • 我从 Kernighan & Ritchie 那里学到了东西,但现在这对孩子们来说可能有点老套了。
  • @GMW:是的,但不需要转换为void*。对于可变参数函数,所有指针参数都提升为void*(C99 §6.5.2.2/7)。
【解决方案2】:

你尝试了什么价值?正如您所说,您知道未签名与已签名的区别。那么它做了什么,你期待什么?

正符号值看起来与无符号值相同,所以我可以假设您使用较小的值进行测试吗?负值呢?

最后,如果您尝试打印变量的地址(如您所见),请改用 %p。

【讨论】:

    【解决方案3】:

    所有地址都是无符号的 32 位或 64 位,具体取决于机器(不能写入负地址)。 %d 的使用是不合适的,但通常会起作用。建议使用 %u 或 %ul。

    【讨论】:

      【解决方案4】:

      %u 将整数视为无符号,而%d 将整数视为有符号。如果整数介于 0 和 INT_MAX 之间(在 32 位系统上为 231-1),则两种情况的输出相同。

      仅当整数为负数(对于有符号输入)或在 INT_MAX+1UINT_MAX 之间(例如,在 231 和 232 之间时,它才会有所不同- 1)。在这种情况下,如果您使用 %d 说明符,您将得到一个负数,而如果您使用 %u,您将得到一个很大的正数。

      地址仅作为无符号数字才有意义,因此没有任何理由将它们打印为有符号数字。此外,当它们被打印出来时,它们通常以十六进制打印(带有%x 格式说明符),而不是十进制。

      不过,您实际上应该只对地址使用%p 格式说明符——它保证适用于所有有效指针。如果您在一个具有 32 位整数但 64 位指针的系统上,如果您尝试使用 %d%u%x 中的任何一个打印指针,而没有 ll 长度修饰符,您将得到错误的结果以及稍后打印的任何其他内容(因为printf 只读取了指针参数的 8 个字节中的 4 个);如果您确实添加了 ll 长度修饰符,那么您将无法移植到 32 位系统。

      底线:始终使用%p 打印出指针/地址:

      printf("The address of n is: %p\n", &n);
      // Output (32-bit system): "The address of n is: 0xbffff9ec"
      // Output (64-bit system): "The address of n is: 0x7fff5fbff96c"
      

      确切的输出格式是实现定义的(C99 §7.19.6.1/8),但它几乎总是被打印为无符号十六进制数字,通常带有前导 0x

      【讨论】:

      • 解释得很好。你能不能给一个单行例如如何使用 %p 格式说明符。
      • 在 C99 中,inttypes.h 中还定义了几个宏,它们在打印指针时为您提供了更大的灵活性。 %p 总是打印一个十六进制地址。但是假设您想以十进制(或八进制!)打印它。 printf("Decimal: %" PRIuPTR ", Octal: %" PRIoPTR "\n", (uintptr_t)p, (uintptr_t)p);
      • C 书可能是在 %p 添加到库之前编写的。
      • @rlibby:非常正确;但是,由于正确使用它们非常痛苦(而且非常丑陋,IMO),因此在实践中很少使用它们。在我所见过的 99.9% 的情况下,指针只会被打印出来用于调试目的,在这种情况下,您确切地知道您正在运行的架构,所以使用 %08x%016llx 没有任何问题。跨度>
      • 这篇文章可能没有明确指出%u%d 都会导致未定义的行为;通常,使用错误的格式说明符也会导致未定义的行为。没有指定“将整数解释为无符号”,无论这意味着什么; printf 函数无法检测您传入的类型并将其转换为正确的类型。一个可能的场景(这篇文章描述的)是编译器发出的代码如果你传入了一个 unsigned int 就会读取一个 unsigned int ;所以你最终会得到与你传入的值具有相同位模式的 unsigned int。
      【解决方案5】:

      没有这样的区别,如果你刚刚开始学习指针,请不要感到困惑。 %u 用于未签名的。而 %d 用于已签名的

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-08-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多