C99:为什么%lli在64位机器上不匹配int64_t?

时间:2016-07-04 08:50:03

标签: c gcc printf c99

我正在将32位ARM代码移植到64位x86并发出以下错误:

format '%lli' expects argument of type 'long long int',
but argument 3 has type 'int64_t'

我发现了很多关于在这种情况下使用PRIi64的信息,但没有提及“为什么我不能使用lli?”。

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

int main() {
    int64_t hugo = 993;
    long long int fred = 994;
    printf("%s -> %" PRIi64 " lli -> %lli\n", PRIi64, hugo, fred);
    return 0;
}

上面的代码编译没有错误并打印li -> 993 lli -> 994。那么,如果两者具有相同的大小,为什么我需要li用于int64_t(8字节)和lli用于long long int(8字节)?

我发现有一篇文章说它是a portability issue warning。因此关闭此警告是保存的吗? (我找到的唯一标志是-Wno-format,它禁用了很多检查......)

1 个答案:

答案 0 :(得分:0)

编写标准时,许多实现都有两个或更多具有相同大小和表示的整数类型;最典型的是,intshortlong具有相同的大小和代表性。

即使在尺寸和表示形式匹配的平台上,从int*short*long*的转换也需要强制转换,但是对于使用相同表示形式的实现需要两个(或者更多)类型,指向其中任何一个的指针可用于访问另一个的数据。对这种用法的支持不被认为是C的“扩展”,而是更多的“好吧,它还能做什么?”这似乎很明显,不需要文档(*)

然而,gcc的作者假设没有指向非字符整数类型的指针将用于访问任何其他非字符整数类型的东西 - 甚至那些大小和表示相同的 EM>。由于printf会使用long long int*来读取%lld的参数,因此long*会为%ld读取一个参数,而int*会读取%d一个用于%lld,gcc的作者将查看任何尝试使用int64_t处理类型long long的参数作为未定义行为的实现,其中该类型被定义为除{之外的其他类型{1}},即使它的大小和表示符合预期。

(*)虽然C89要求记录所有“扩展”,但列出公共扩展名的附件不会列出它。由于标准的作者不可能不知道很多 - 如果不是大多数 - 编译器有两个或多个共享相同大小和表示的整数类型,并允许指向这些类型的指针可以互换使用,唯一合理的结论他们并不认为这种行为是需要文件的“扩展”。