【问题标题】:printf() format specifier for int64_t and uint64_t in 32-bit ANSI C32 位 ANSI C 中 int64_t 和 uint64_t 的 printf() 格式说明符
【发布时间】:2018-07-18 03:12:40
【问题描述】:

我正在编写一些 32 位 ANSI C,使用 gcc 编译,我需要在其中打印一些 64 位有符号和无符号整数。问题是在gcc 32 位C 中,int64_tuint64_t 分别转换为long long int 和unsigned long long int,格式说明符%lld%llu 不被ANSI 支持C. 使用inttypes.h 中提供的格式说明符宏也无济于事,因为它们会转换为%lld%llu

以下代码编译失败:

#include <stdio.h>
#include <inttypes.h>

int main() {
    uint64_t some_int = 123456789;
    printf("Your int is: %"PRId64"\n", some_int);
    return 0;
}

使用gcc main.c -ansi -Og -g -m32 -Wall -Werror -Wextra -pedantic编译

错误信息是:

error: ISO C90 does not support the ‘ll’ gnu_printf length modifier [-Werror=format=]

所以,我的问题是:我应该使用什么格式说明符来打印 32 位 ANSI C 中的双倍长度整数?

【问题讨论】:

  • 所谓的ANSI C 实际上是 ISO 标准化 C 的先驱。它也非常古老,除非你有一个同样旧的编译器,否则你至少应该尝试使用the C99 standard。如今,即使是 Microsoft Visual C 编译器也支持大部分 C99。
  • "它失败了..." - 你看到了什么错误?
  • @tmaxthomas:使用此命令行的代码没有编译器错误。
  • 因为uint64_t 是在 C99 标准中引入的,所以在旧编译器中确实没有可移植的方法来处理 64 位整数。为什么要将其移植到旧标准?考虑到很久以前所有三个大型编译器(GCC、Clang 和 MSVC)现在都支持 C99(甚至是全部或大部分 C11),我真的看不出有什么理由。
  • 术语“ANSI C”通常用来指代 1989 年 ANSI C 标准定义的语言,它与 1990 年 ISO C 标准定义的语言相同(后来被 ANSI 采用) )。 C 标准的 1999 和 2011 版本由 ISO 发布,然后被 ANSI 正式采用。因此,该组织 ANSI 承认 ISO C11 为当前的 C 标准。由于“ANSI C”含糊不清,我建议您参考标准的年份。通过“ANSI C”,我怀疑您的意思是 C90(也可以称为 C89)。

标签: c


【解决方案1】:

确保您可以在 C89 编译器中使用 64 位整数的一种方法:

#include <stdio.h>
#include <assert.h>
#include <limits.h>
typedef unsigned long uint64_t;

int main() {
    uint64_t some_int = 123456789;
    assert(CHAR_BIT * sizeof(long) >= 64);
    printf("Your int is: %lu\n", some_int);
    return 0;
}

【讨论】:

  • 这并不能确保你有 64 位整数,如果你的编译器没有提供它们,它根本无法编译。
  • 如果这是您需要的,这可能很有用,但这不是 OP 所要求的。
  • 实际上(我相信 Keith 知道这一点)它在 run-time 中止(我觉得使用负数组大小的编译时“断言”是如果long 小于 64 位。但如果它运行,则可以保证您拥有 64 位整数。除非您使用售后市场的多精度软件包,否则您在 C89 中获得 64 位的唯一方法是供应商提供它们。
  • 你是对的,它在编译时中止,而不是在运行时中止。 (C89/C90 没有#error)。我仍然认为这不能回答问题。
  • @KeithThompson,缺少#error 的 C89 是我的 N843 草案和 K&R2 副本的新闻。在任何情况下,在 C89 的约束范围内,如果 long 至少为 64 位,那么这就是打印此类值的方式。
【解决方案2】:

短语“ANSI C”通常指的是由 1989 ISO C 标准定义的语言。 1990 ISO C 标准描述了完全相同的语言(它添加了一些 ISO 强制部分)。 ANSI 正式放弃了自己的 1989 标准并采用了 ISO 标准——并且还采用了 1999 和 2011 版的 ISO C 标准。所以ANSI定义的C标准是2011 ISO C标准。

由于这种含糊不清,我建议避免使用“ANSI C”这一短语,并提及 ISO 发布标准的年份:C90、C99 或 C11。

我应该使用什么格式说明符来打印 32 位 ANSI C 中的双倍长度整数?

没有。

C90 不支持 and 标头或类型 long long。它不需要支持任何 64 位整数类型(long 可能是 64 位,但通常是 32 位)。因为这些类型不存在,printf 没有为它们提供格式说明符。

原则上,您可以使用支持 64 位 long 的 C90 实现(牺牲可移植性),或者您可以使用更窄的整数数组实现自己的 64 位类型,将操作作为函数提供。

如果您可以更新您的问题以准确解释为什么您希望将自己限制在 29 岁的 C 标准版本中,或许可以提供更有用的答案。我只想告诉你使用支持 C99 或 C11 的实现,但你已经指出这不是解决方案(没有解释原因)。

【讨论】:

  • -ansi 替换为-std=c99(或-std=c11 以使用C11 标准)可以解决此问题。我怀疑-ansi 开关在这里误导了人们,因为它看起来像是在 GCC 中启用“标准 C”模式的好方法。那个开关的名字真的很不幸。
猜你喜欢
  • 1970-01-01
  • 2012-05-17
  • 2012-05-17
  • 1970-01-01
  • 2017-11-16
  • 2016-12-16
  • 1970-01-01
  • 2011-03-11
相关资源
最近更新 更多