【问题标题】:How do you format an unsigned long long int using printf?如何使用 printf 格式化 unsigned long long int?
【发布时间】:2010-09-05 09:28:32
【问题描述】:
#include <stdio.h>
int main() {
    unsigned long long int num = 285212672; //FYI: fits in 29 bits
    int normalInt = 5;
    printf("My number is %d bytes wide and its value is %ul. A normal number is %d.\n", sizeof(num), num, normalInt);
    return 0;
}

输出:

My number is 8 bytes wide and its value is 285212672l. A normal number is 0.

我认为这个意外结果来自打印unsigned long long int。你怎么printf()unsigned long long int

【问题讨论】:

  • 我刚刚用 gcc 编译了你的代码(用 %llu ),输出是正确的。您是否将任何选项传递给编译器?
  • 请注意,samsung bada 的 newlib 似乎不支持 "%lld" : developer.bada.com/forum/…
  • 我建议使用 stdint.h 并明确说明变量中的位数。我们仍处于 32 位和 64 位架构之间的过渡期,“unsigned long long int”在两者上的含义并不相同。

标签: c syntax printf format-specifiers long-long


【解决方案1】:

在 u(无符号)转换中使用 ll (el-el) long-long 修饰符。 (适用于 Windows,GNU)。

printf("%llu", 285212672);

【讨论】:

  • 或者更准确地说是用于 GNU libc,并且不适用于 Microsoft 的 C 运行时。
  • 这不是 Linux/UNIX 的东西,“ll”长度修饰符是在 C99 中添加到标准 C 中的,如果它在“Microsoft C”中不起作用,那是因为它们不是符合标准。
  • 在 VS2008 中为我工作。此外,据我所知,MS C 编译器(当设置为直接编译 C 时)应该在设计上符合 C90 标准; C99 介绍了一些不是所有人都喜欢的东西。
  • 这里要记住的一件事是,如果您将多个long long 参数传递给printf 并为其中一个使用错误格式,例如@987654324 @ 而不是 %lld,那么即使是打印的参数 after 不正确的参数也可能完全关闭(或者甚至可能导致 printf 崩溃)。本质上,变量参数是在没有任何类型信息的情况下传递给 printf 的,所以如果格式字符串不正确,结果是不可预测的。
  • 听到 Herb Sutter 在接受采访时说,微软的客户不需要 C99,所以他们的纯 C 编译器已经冻结在 C90。这适用于编译为 C 的情况。如果编译为 C++,正如上面其他人所指出的,你应该没问题。
【解决方案2】:

%d--> 代表int

%u--> 代表unsigned int

%ld--> 代表long intlong

%lu--> 代表unsigned long intlong unsigned intunsigned long

%lld--> 代表long long intlong long

%llu--> 代表unsigned long long intunsigned long long

【讨论】:

    【解决方案3】:

    您可能想尝试使用 inttypes.h 库,它为您提供类型,例如 int32_tint64_tuint64_t 等。 然后您可以使用它的宏,例如:

    uint64_t x;
    uint32_t y;
    
    printf("x: %"PRId64", y: %"PRId32"\n", x, y);
    

    这是“保证”不会给您带来与longunsigned long long 等相同的麻烦,因为您不必猜测每种数据类型中有多少位。

    【讨论】:

    • 这些PRId64PRId32 宏定义在哪里?
    • @happy_marmoset:它们在inttypes.h中定义
    • 我认为您需要 PRIu64PRIu32 来获取无符号整数。
    • inttypes.h 是标准的吗?不会是stdint.h吗?
    • 请注意,这些精确宽度类型是可选的,因为有些架构没有这些精确宽度的整数类型。只有leastXfastX 类型(实际上可能比指定的更宽)是强制性的。
    【解决方案4】:

    对于使用 MSVS 的 long long(或 __int64),您应该使用 %I64d:

    __int64 a;
    time_t b;
    ...
    fprintf(outFile,"%I64d,%I64d\n",a,b);    //I is capital i
    

    【讨论】:

      【解决方案5】:

      这是因为 %llu 在 Windows 下无法正常工作,并且 %d 无法处理 64 位整数。我建议改用 PRIu64,您会发现它也可以移植到 Linux。

      试试这个:

      #include <stdio.h>
      #include <inttypes.h>
      
      int main() {
          unsigned long long int num = 285212672; //FYI: fits in 29 bits
          int normalInt = 5;
          /* NOTE: PRIu64 is a preprocessor macro and thus should go outside the quoted string. */
          printf("My number is %d bytes wide and its value is %" PRIu64 ". A normal number is %d.\n", sizeof(num), num, normalInt);
          return 0;
      }
      

      输出

      My number is 8 bytes wide and its value is 285212672. A normal number is 5.
      

      【讨论】:

      • +1 用于引用我从未见过的 PRIu64,但这似乎不能移植到 64 位 Linux(至少),因为 PRIu64 扩展为“lu”而不是“llu”。
      • 那为什么不好呢? long 是 64 位 Linux 上的 64 位值,与除 Windows 之外的所有其他操作系统一样。
      • @BDatRivenhill Linux/Unix 使用 LP64,其中 long 为 64 位
      • 然而,为了使其更便携,请改用int64_t,因为很可能有些实现的 long long 大于 long
      • "%" PRIu64 匹配 uint64_t"%llu" 匹配 unsigned long long。这个答案有"%" PRIu64unsigned long long。当unsigned long long 超过 64 位时,这种方法会为 UB 播种。最好避免。
      【解决方案6】:

      在 Linux 中为 %llu,在 Windows 中为 %I64u

      虽然我发现它在 Windows 2000 中不起作用,但那里似乎有一个错误!

      【讨论】:

      • 对于 windows,(或至少,对于 windows 的 microsoft C 编译器)还有 %I64d、%I32u 和 %I32d
      • 它与 Windows 2000 有什么关系? C 库是处理 printf 的库。
      • 正是我观察到的。我编写了一个使用这种结构的应用程序,它在 WinXP 上完美运行,但在 Win2k 上吐出垃圾。也许这与 C 库对内核进行的系统调用有关,也许与 Unicode 有关,谁知道呢。我记得必须使用 _i64tot() 或类似的东西来解决它。
      • Win2k/Win9x 问题可能是由于 unsigned long long 数据类型相对较新(当时采用 C99 标准),但 C 编译器(包括 MinGW/GCC)利用旧的 Microsoft C 运行时仅支持 C89 规范。我只能访问真正古老且相当新的 Windows API 文档。所以很难准确地说出I64u 支持何时加入。但听起来像是XP 时代。
      【解决方案7】:

      用VS2005编译成x64:

      %llu 效果很好。

      【讨论】:

        【解决方案8】:

        显然,自 2008 年以来,十多年来没有人提出多平台* 解决方案,所以我将附上我的 ?。请点赞。 (开玩笑。我不在乎。)

        解决方案:lltoa()

        使用方法:

        #include <stdlib.h> /* lltoa() */
        // ...
        char dummy[255];
        printf("Over 4 bytes: %s\n", lltoa(5555555555, dummy, 10));
        printf("Another one: %s\n", lltoa(15555555555, dummy, 10));
        

        OP 的例子:

        #include <stdio.h>
        #include <stdlib.h> /* lltoa() */
        
        int main() {
            unsigned long long int num = 285212672; // fits in 29 bits
            char dummy[255];
            int normalInt = 5;
            printf("My number is %d bytes wide and its value is %s. "
                "A normal number is %d.\n", 
                sizeof(num), lltoa(num, dummy, 10), normalInt);
            return 0;
        }
        

        %lld 打印格式字符串不同,这对我在 Windows 上的 32 位 GCC 下工作。

        *) 嗯,几乎是多平台的。在 MSVC 中,您显然需要 _ui64toa() 而不是 lltoa()

        【讨论】:

        • 我没有lltoa
        • lltoa() 不是标准 C 库函数。除非允许非标准扩展,否则编译时它在 Windows 上的 32 位 GCC 下不起作用。
        • sizeof(num) 返回size_t"%d" 没有指定使用它。 "%zu" 更好。
        【解决方案9】:

        除了人们多年前写的:

        • 您可能会在 gcc/mingw 上收到此错误:

        main.c:30:3: warning: unknown conversion type character 'l' in format [-Wformat=]

        printf("%llu\n", k);

        那么你的mingw版本不默认为c99。添加此编译器标志:-std=c99

        【讨论】:

          【解决方案10】:

          如何使用printf 格式化unsigned long long int

          从 C99 开始,在转换说明符 o,u,x,X 之前使用 "ll" (ell-ell)。

          许多答案中除了base 10选项外,还有base 16和base 8选项:

          选择包括

          unsigned long long num = 285212672;
          printf("Base 10: %llu\n", num);
          num += 0xFFF; // For more interesting hex/octal output.
          printf("Base 16: %llX\n", num); // Use uppercase A-F
          printf("Base 16: %llx\n", num); // Use lowercase a-f
          printf("Base  8: %llo\n", num);
          puts("or 0x,0X prefix");
          printf("Base 16: %#llX %#llX\n", num, 0ull); // When non-zero, print leading 0X
          printf("Base 16: %#llx %#llx\n", num, 0ull); // When non-zero, print leading 0x
          printf("Base 16: 0x%llX\n", num); // My hex fave: lower case prefix, with A-F
          

          输出

          Base 10: 285212672
          Base 16: 11000FFF
          Base 16: 11000fff
          Base  8: 2100007777
          or 0x,0X prefix
          Base 16: 0X11000FFF 0
          Base 16: 0x11000fff 0
          Base 16: 0x11000FFF
          

          【讨论】:

          • +l: "%llu" 让我吃惊。我使用“%ull”并收到警告说我提供了int
          • @Rainning "%ull" 打印一个unsigned,然后是"ll"
          【解决方案11】:

          非标准的东西总是很奇怪:)

          对于长长的部分 在 GNU 下它是 Lllq

          在 windows 下我相信它只是 ll

          【讨论】:

            【解决方案12】:

            嗯,一种方法是使用 VS2008 将其编译为 x64

            这会像你期望的那样运行:

            int normalInt = 5; 
            unsigned long long int num=285212672;
            printf(
                "My number is %d bytes wide and its value is %ul. 
                A normal number is %d \n", 
                sizeof(num), 
                num, 
                normalInt);
            

            对于 32 位代码,我们需要使用正确的 __int64 格式说明符 %I64u。于是就变成了。

            int normalInt = 5; 
            unsigned __int64 num=285212672;
            printf(
                "My number is %d bytes wide and its value is %I64u. 
                A normal number is %d", 
                sizeof(num),
                num, normalInt);
            

            此代码适用于 32 位和 64 位 VS 编译器。

            【讨论】:

            • 尝试一个实际的 64 位数字而不是 '285212672',我不相信第一个示例运行正确,编译到任何目标。
            【解决方案13】:

            十六进制:

            printf("64bit: %llp", 0xffffffffffffffff);
            

            输出:

            64bit: FFFFFFFFFFFFFFFF
            

            【讨论】:

            • 非常好!我想知道如何以十六进制表示形式获得它
            • 但是,几乎所有的 C++ 和 C 编译器都会给出警告:警告:使用带有 'p' 类型字符的 'll' 长度修饰符 [-Wformat=]跨度>
            • 这个完全错误的答案具有双重未定义行为,甚至没有开始回答问题
            • @AnttiHaapala 你说这个答案完全被双重未定义的行为所破坏,你能详细说明还是我应该删除它?还是把它当作一个好的坏例子?
            • UB1:所有指针大小相同,sizeof(char *) == sizeof(long long *),因此 %p 上的大小修饰符毫无意义。 UB2:0xff.fff 是 int 类型,格式 %p 需要一个指针
            猜你喜欢
            • 2016-07-29
            • 1970-01-01
            • 2012-01-27
            • 1970-01-01
            • 1970-01-01
            • 2016-12-20
            • 1970-01-01
            • 2011-05-01
            相关资源
            最近更新 更多