【问题标题】:string format for intptr_t and uintptr_tintptr_t 和 uintptr_t 的字符串格式
【发布时间】:2011-08-13 08:24:56
【问题描述】:

intptr_t uintptr_t 的字符串格式对 32 位和 64 位架构都有效。

编辑

warning: format ‘%x’ expects type ‘unsigned int’, but argument 2 has type "AAA"

这是我在 64 位而不是 32 位中收到的警告。

  intptr_t  AAA

【问题讨论】:

    标签: c formatting printf scanf


    【解决方案1】:

    这将是来自inttypes.h 的以下宏:

    对于printfPRIdPTR PRIiPTR PRIoPTR PRIuPTR PRIxPTR PRIXPTR

    对于scanfSCNdPTR SCNiPTR SCNoPTR SCNuPTR SCNxPTR

    使用示例:

    uintptr_t p = SOME_VALUE;
    printf("Here's a pointer for you: %" PRIxPTR "\n", p);
    

    【讨论】:

    • 使用示例:uinptr_t p = SOME_VALUE; printf("Here's a pointer for you: %" PRIxPTR "\n", p);
    • 感谢您的回答,我的问题可能不是那么精确......如果有像 "%d" 这样的强格式表示整数等,我到底想知道什么在。根据硬件架构,我收到了一些警告。我已经编辑了我的问题。
    【解决方案2】:

    我认为您应该考虑使用“z”修饰符。这将转换任何对应于 size_t og ssize_t 的东西,我发现它也适用于 (u)intptr_t。

    例如:

    intptr_t ip = ...; printf("ip = %zd\n", ip);

    【讨论】:

    • 恭喜,您发现了未定义的行为。
    • @AnttiHaapala void *p = ...; printf("%td", (ptrdiff_t)p); 会是(同一种)UB 吗?
    【解决方案3】:

    %p 应该可以替代%x,因为uintptr_t 被定义为与平台上的指针大小相同的无符号整数。

    编辑:不幸的是,至少在我的编译器上,您必须将变量转换为 (void *)。但是,我认为将 uintptr_t 转换为指针是安全的。

    【讨论】:

      【解决方案4】:

      我正在一个环境中编译一些代码,由于某种原因没有inttypes.h 中定义了PRI.PTR 宏,其中intptr_t 被定义为int 32 位和long int 64 位。

      我通过使用%li 格式说明符并在printf 参数中将变量转换为long int 来绕过警告。这是安全的在此环境中,因为如上所述,intptr_t 永远不能长于long int

      如果可以避免,我不建议使用此解决方案,但它至少解决了警告。

      【讨论】:

        【解决方案5】:

        我认为即使long int 也不安全,您应该尝试long long int,它必须存在,因为您正在使用 64 位架构并且您已经拥有intptr_t

        在某些 64 位架构上(我认为 Microsoft Windows 会如此),long int 可能会保持 32 位宽度,以满足 MS-DOS 时代的假设,即short int 始终是 16 位并且long int 始终为 32 位。

        即使在那些具有 32 位 long intprintf("%llx", (unsigned long long)AAA); 的平台上也可以工作。如果可能的话,您应该考虑更可取的形式printf("%jx", (uintmax_t)AAA);

        请注意,对于某些旧编译器,您可能需要使用 "%Lx"(对于 GNU C,转换为 unsigned long long)或 "%I64x"(对于 Visual C++,转换为 __uint64)用于 64 位整数.

        P。 S。 %p 在这种情况下可能不好,因为 %p 可能会在十六进制之前打印裸字 0x 和/或可能会打印零填充值。如果两者都应用,例如,代码printf("%p\n", (void*)16); 将在 32 位平台上打印0x00000010,在 64 位平台上打印0x0000000000000010;发帖人应该希望只打印10

        【讨论】:

          【解决方案6】:
          ####################################### CPP type proving code (identifying type by typeid)
          $ cat typeid.cpp
          #include <stdio.h>
          #include <stddef.h>
          #include <stdint.h>
          #include <time.h>
          #include <typeinfo>
          
          #define name(t) printf("%30s : %s\n", #t, typeid(t).name())
          
          // g++|clang++ -o ./typeid.exe typeid.cpp -m32 && ./typeid.exe
          // g++|clang++ -o ./typeid.exe typeid.cpp -m64 && ./typeid.exe
          int main(int argc, char* argv[]) {
              name(ptrdiff_t);
              name(intptr_t);
              name(uintptr_t);
          
              return 0;
          }
          
          ####################################### C type proving code (identifying type by _Generic)
          $ cat typeid.c 
          #include <stdio.h>
          #include <stdint.h>
          #include <stddef.h>
          #include <time.h>
          
          /* matches the type name of an expression */
          #define name_match(e) _Generic((e), \
                           _Bool: "_Bool", \
                            char: "char", \
                     signed char: "signed char", \
                   unsigned char: "unsigned char", \
                           short: "short", \
                  unsigned short: "unsigned short", \
                             int: "int", \
                    unsigned int: "unsigned int", \
                            long: "long", \
                   unsigned long: "unsigned long", \
                       long long: "long long", \
              unsigned long long: "unsigned long long", \
                           float: "float", \
                          double: "double", \
                     long double: "long double", \
                         default: "unknown")
          
          #define name(t, e) printf("%30s : %s\n", #t, name_match(e))
          
          int main() {
              ptrdiff_t ptrdiff_v = 0;
              intptr_t  intptr_v = 0;
              uintptr_t uintptr_v = 0;
          
              name(ptrdiff_t, ptrdiff_v);
              name(intptr_t,  intptr_v);
              name(uintptr_t, uintptr_v);
          }
          
          ####################################### run in arch32
          $ clang++ -o ./typeid.exe typeid.cpp -m32 && ./typeid.exe
                               ptrdiff_t : i
                                intptr_t : i
                               uintptr_t : j
          
          $ clang -o ./typeid.exe typeid.c -m32 && ./typeid.exe      
                               ptrdiff_t : int
                                intptr_t : int
                               uintptr_t : unsigned int
          result:
               intptr_t == ptrdiff_t
              uintptr_t == unsigned ptrdiff_t
          
          ####################################### run in arch64
          $ clang++ -o ./typeid.exe typeid.cpp -m64 && ./typeid.exe
                               ptrdiff_t : l
                                intptr_t : l
                               uintptr_t : m
          
          $ clang -o ./typeid.exe typeid.c -m64 && ./typeid.exe   
                               ptrdiff_t : long
                                intptr_t : long
                               uintptr_t : unsigned long
          result:
               intptr_t == ptrdiff_t
              uintptr_t == unsigned ptrdiff_t
          
          ####################################### man 3 printf
          t -- A following integer conversion corresponds to a ptrdiff_t argument.
          
          ####################################### conclusion
          //  intptr_t == ptrdiff_t
          // uintptr_t == unsigned ptrdiff_t
          // so:
          //     1)  intptr_t has string format %td
          //     2) uintptr_t has string format %tu
          
          #include <stdio.h>
          #include <stdint.h>
          
          int main(int argc, char *argv[]) {
              intptr_t  x = 0;
              uintptr_t y = 0;
          
              scanf("%td %tu", &x, &y);
              printf("out: %td %tu\n", x, y);
              return 0;
          }
          

          【讨论】:

          • 抱歉,这个问题是用 C 标记的,所以为什么要用 cpp 解决方案来回答?
          • 使用 '#include ' 需要 cpp 后缀。据我所知,printf是C函数,不是CPP函数,std::printf是CPP函数。
          • @Stargateur 你说这是cpp方案,就因为有cpp后缀?
          • typeid 在 C 中不存在,太棒了。
          • 为 C 添加了一个 __Generic 版本。
          猜你喜欢
          • 2017-04-17
          • 2014-06-02
          • 2015-10-10
          • 2016-07-24
          • 1970-01-01
          • 2012-05-11
          • 2019-04-22
          • 2019-03-04
          • 2012-10-22
          相关资源
          最近更新 更多