首页 文章

如何使用printf系列便携地打印size_t变量?

提问于
浏览
303

我有一个 size_t 类型的变量,我想用 printf() 打印它 . 我使用什么格式说明符来便携地打印它?

在32位机器中, %u 似乎是对的 . 我用g -g -W -Wall -Werror -ansi -pedantic编译,没有警告 . 但是当我在64位机器中编译该代码时,它会产生警告 .

size_t x = <something>;
printf( "size = %u\n", x );

warning: format '%u' expects type 'unsigned int', 
    but argument 2 has type 'long unsigned int'

如果我将其更改为 %lu ,警告会如预期的那样消失 .

问题是,如何编写代码,以便在32位和64位机器上编译警告?

编辑:我猜一个答案可能是将"cast"变量变成 unsigned long ,并使用 %lu 进行打印 . 这在两种情况下都有效 . 我在寻找是否还有其他想法 .

12 回答

  • 6

    对于那些谈论在C中做这个并不一定支持C99扩展的人,我衷心推荐boost :: format . 这使得size_t类型大小问题没有实际意义:

    std::cout << boost::format("Sizeof(Var) is %d\n") % sizeof(Var);
    

    由于您不需要boost :: format中的大小说明符,因此您可以担心如何显示该值 .

  • 0
    printf("size = %zu\n", sizeof(thing) );
    
  • 75

    使用 z 修饰符:

    size_t x = ...;
    ssize_t y = ...;
    printf("%zu\n", x);  // prints as unsigned decimal
    printf("%zx\n", x);  // prints as hex
    printf("%zd\n", y);  // prints as signed decimal
    
  • 6

    看起来它取决于您正在使用的编译器(blech):

    ...当然,如果您使用的是C,则可以使用 cout 代替suggested by AraK .

  • 51

    对于C89,使用 %lu 并将值转换为 unsigned long

    size_t foo;
    ...
    printf("foo = %lu\n", (unsigned long) foo);
    

    对于C99及更高版本,请使用 %zu

    size_t foo;
    ...
    printf("foo = %zu\n", foo);
    
  • -4

    扩展Adam Rosenfield对Windows的回答 .

    我在VS2013 Update 4和VS2015预览版上测试了这段代码:

    // test.c
    
    #include <stdio.h>
    #include <BaseTsd.h> // see the note below
    
    int main()
    {
        size_t x = 1;
        SSIZE_T y = 2;
        printf("%zu\n", x);  // prints as unsigned decimal
        printf("%zx\n", x);  // prints as hex
        printf("%zd\n", y);  // prints as signed decimal
        return 0;
    }
    

    VS2015生成二进制输出:

    1 1 2

    而由VS2013生成的那个说:

    zu zx zd

    注意: ssize_t 是POSIX扩展, SSIZE_TWindows Data Types中类似,因此我添加了 <BaseTsd.h> 参考 .

    此外,除了以下C99 / C11标头外,所有C99标头都可在VS2015预览中使用:

    C11 - <stdalign.h>
    C11 - <stdatomic.h>
    C11 - <stdnoreturn.h>
    C99 - <tgmath.h>
    C11 - <threads.h>
    

    此外,C11的 <uchar.h> 现已包含在最新预览中 .

    有关更多详细信息,请参阅此oldnew列表以获取标准一致性 .

  • 5
    std::size_t s = 1024;
    std::cout << s; // or any other kind of stream like stringstream!
    
  • 2

    正如AraK所说,c stream接口将始终可移植 .

    std :: size_t s = 1024; std :: cout << s; //或者像stringstream一样的任何其他类型的流!

    如果你想要C stdio,对于某些“便携式”的情况,没有可解决的问题 . 它变得丑陋,因为你看到,选择错误的格式标志可能会产生编译器警告或提供不正确的输出 .

    C99试图用inttypes.h格式解决这个问题,比如“%”PRIdMAX“\ n” . 但就像“%zu”一样,并非所有人都支持c99(如2013年之前的MSVS) . 有“msinttypes.h”文件浮动来处理这个问题 .

    如果您转换为其他类型,根据标志,您可能会收到编译器警告,要求截断或更改符号 . 如果你走这条路线,选择一个更大的相关固定尺寸类型 . 一个无符号长long和“%llu”或无符号长“%lu”应该可以工作,但是llu也可能会减慢32位世界中的速度 . (编辑 - 我的mac发出64位警告,因为%llu不匹配size_t,即使%lu,%llu和size_t都是相同的大小 . %lu和%llu在我的MSVS2012上的大小不同 . 所以你可能需要使用匹配的格式 . )

    就此而言,您可以使用固定大小类型,例如int64_t . 可是等等!现在我们回到c99 / c 11,旧的MSVS再次失败 . 另外你还有强制转换(例如map.size()不是固定大小的类型)!

    您可以使用第三方 Headers 或库,例如boost . 如果您还没有使用过,那么您可能不希望以这种方式对项目进行膨胀 . 如果您愿意为此问题添加一个,为什么不使用c流或条件编译?

    因此,您需要使用c流,条件编译,第三方框架或适合您的便携式设备 .

  • -1

    如果将32位无符号整数传递给%lu格式,它会警告你吗?它应该没问题,因为转换是明确定义的,不会丢失任何信息 .

    我听说有些平台在 <inttypes.h> 中定义了宏,你可以插入到格式字符串文字中,但我在Windows C编译器上看不到那个 Headers ,这意味着它可能不是跨平台的 .

  • -3

    C99为此定义了"%zd"等 . (感谢评论者)C中没有可移植格式说明符 - 你可以使用 %p ,这两个场景中的woulkd字,但也不是便携式选择,并以十六进制给出值 .

    或者,使用一些流式传输(例如串流)或安全的printf替换,例如Boost Format . 据我所知,这个建议仅限于使用(并且需要C) . (我们已经在实现unicode支持时,我们使用了类似的方法来满足我们的需求 . )

    C的基本问题是使用省略号的printf在设计上是不安全的 - 它需要根据已知参数确定附加参数的大小,因此无法修复它以支持“无论你得到什么” . 因此,除非您的编译器实现某些专有扩展,否则您运气不佳 .

  • 10

    在某些平台上,对于某些类型,有特定的printf转换说明符可用,但有时必须使用转换为更大的类型 .

    我在这里记录了这个棘手的问题,使用示例代码:http://www.pixelbeat.org/programming/gcc/int_types/并定期更新新平台和类型的信息 .

  • 379

    如果要将size_t的值打印为字符串,可以执行以下操作:

    char text[] = "Lets go fishing in stead of sitting on our but !!";
    size_t line = 2337200120702199116;
    
    /* on windows I64x or I64d others %lld or %llx if it works %zd or %zx */
    printf("number: %I64d\n",*(size_t*)&text);
    printf("text: %s\n",*(char(*)[])&line);
    

    结果是:

    号码:2337200120702199116

    文字:让我们去钓鱼,而不是坐在我们身上!

    编辑:重新阅读问题因为投票结果我注意到他的问题不是%llu或%I64d但是不同机器上的size_t类型看到这个问题https://stackoverflow.com/a/918909/1755797
    http://www.cplusplus.com/reference/cstdio/printf/

    size_t在32位机器上是unsigned int,在64位机器上是unsigned long long int
    但是%ll总是期望一个unsigned long long int .

    size_t在不同的操作系统上的长度不同,而%llu是相同的

相关问题