【问题标题】:Alternative for "%p" format specifier“%p”格式说明符的替代品
【发布时间】:2015-02-13 01:34:40
【问题描述】:

我在嵌入式系统(特别是 PIC 上的 XC8)上使用平台/编译器,它不包含 printf() 的 %p 指针地址格式说明符。

例如:

printf("J: %f [@ 0x%p]\r\n", j, &j);

将在大多数编译器中显示名为“j”的变量的值和地址。但是,根据编译器文档,它不包括对 %p 的支持。给出错误“无效的格式说明符或类型修饰符”。

那么在这种情况下,除了打印变量的地址之外,还有什么替代方法呢?

【问题讨论】:

  • 尝试%lx并将地址转换为(unsigned long)

标签: c embedded microcontroller


【解决方案1】:

通常情况下,您将使用 <inttypes.h> 标头、uintptr_t 类型和 PRIXPTRPRIxPTR 格式(最初在 C99 或 ISO/IEC 9899:1999 中正式定义):

printf("J: %f [@ 0x%" PRIXPTR "]\r\n", j, (uintptr_t)&j);

但是,如果您没有%p,您可能也没有这些,因此您可能不得不依靠:

printf("J: %f [@ 0x%lX]\r\n", j, (unsigned long)&j);

假设sizeof(unsigned long) == sizeof(void *);如果没有,您需要使用整数类型,例如sizeof(other_integer_type) == sizeof(void *)。如果找不到此类类型,则需要详细说明您机器上的类型。

【讨论】:

    【解决方案2】:

    %p 格式通常由运行时库中的printf 函数实现,而不是在编译器中。对于编译器和库不一定来自同一供应商或其他来源的实现来说,这种区别可能很重要。 (一些编译器可能会使用文字格式字符串优化 printf 调用;感谢 chux 指出这一点。)

    正如 Matt McNabb 的评论所暗示的,您很可能将指针转换为 unsigned long 并使用 %lx 打印它。我可能会使用类似的东西:

    printf("J: %f [@ 0x%lx]\r\n", j, (unsigned long)&j);
    

    如果 (a) 指针比 unsigned long 宽或 (b) 从指针类型到 unsigned long 的转换丢失信息,这可能会失败。我研究过一些奇怪的系统,但我从未见过会违反其中任何一个假设的系统。

    由于您的代码可能并不意味着可移植,因此您可以在您的平台上检查指针和unsigned long 的大小。如果您感到偏执,可以添加以下内容:

    assert(sizeof (unsigned long) >= sizeof (void*));
    

    只是为了(几乎)确保转换不会丢失信息。

    【讨论】:

    • "%p 格式由运行时库中的 printf 函数实现,而不是在编译器中。"不一定如此。 PIC 编译器(取决于哪一个)在编译时分析常量格式字符串并形成所需的函数调用。
    • @chux:好点。 gcc 可以进行类似的转换,尽管没有那么激进;例如,printf("hello\n") 可能会产生与 puts("hello"); 等效的代码
    • 嵌入式平台的编译器像这样优化以避免引入整个 printf() 函数 - 通常,它相当大。
    猜你喜欢
    • 2012-09-19
    • 1970-01-01
    • 1970-01-01
    • 2016-02-13
    • 2013-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多