我正在使用C ++中的JNI开发Android的原生插件。我想打印出jlong
值,defined as a 64-bit value。将它直接投射到很长时间是否安全,或者我应该注意哪些特定于平台的问题?
jlong foo = 2;
// This results in the following warning:
// Format specifier '%ld' requires 'long' argument instead of 'jlong'.
printf("%ld", foo);
// This works without a warning.
printf("%ld", (long)foo);
答案 0 :(得分:4)
Java,正如您已经注意到的那样,将long
定义为64位数。 C ++不这样做long
只保证至少与int
一样大,所以它也可能是32位数。
然而,它发生给定组合“Android”+“64位”,实际上long
是64位整数。这与例如Windows仍然只是一个32位整数
因此,假设您只是为64位编写,那么可以在此处停止阅读。
C ++借用C中的<cstdint>
标头,其中定义了int64_t
类型。所以你需要使用你知道的64位类型的东西而你担心它可能不合适?
好吧,使用保证的类型来应对:
#include <cstdio>
using my_jlong = int64_t;
答案 1 :(得分:1)
C ++标准要求long
表示(-2147483647
到2147483647
)的最小值范围,这意味着它可以是32位类型。将jlong
值转换为超出32位类型范围的long
- 如果这是long
对于您的目标实现而言 - 将产生未定义的行为。
-9223372036854775807
可以表示的值所需的最小范围(9223372036854775807
到long long
)意味着它是64位类型(或更好)。
潜在的问题是由边缘情况引起的:特别是极端情况(类型中最大可表示负值或最大正值),因为64位整数类型可以表示偶数个值,其中一个值为零。这意味着64位类型可以表示的正值的数量与它可以表示的负值的数量不同(或多或少)。如果jlong
表示不同于long long
的值范围(例如jlong
表示范围-9223372036854775807
到9223372036854775808
,而long long
表示-9223372036854775808
1}}到9223372036854775807
)然后转换这些极值的结果可能会给出未定义的行为。
简而言之,无法保证long long
能够代表与jlong
完全相同的值范围。实际上,你会发现大多数现代目标平台都没问题。然而,对于一些较旧的系统而言并非如此,并且(理论上至少)将来可能会再次发生变化。
如果您能保证(例如通过分析您的Java代码)您的jlong
永远不会拥有long long
可能无法代表的某个违规极值,那么就不会有问题转换为long long
。如果您可以保证(例如,通过参考每个目标系统和C ++编译器的文档)long long
支持至少与jlong
相同的值范围,那么也没有问题。
使用C ++流(每种标准类型都有重载插入运算符)比使用C I / O(依赖于您正确使用格式字符串)打印效果更好。