将jlong​​投射到很长时间是否安全?

时间:2017-07-09 12:03:37

标签: android c++ android-ndk java-native-interface

我正在使用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);

2 个答案:

答案 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表示(-21474836472147483647)的最小值范围,这意味着它可以是32位类型。将jlong值转换为超出32位类型范围的long - 如果这是long对于您的目标实现而言 - 将产生未定义的行为。

-9223372036854775807可以表示的值所需的最小范围(9223372036854775807long long)意味着它是64位类型(或更好)。

潜在的问题是由边缘情况引起的:特别是极端情况(类型中最大可表示负值或最大正值),因为64位整数类型可以表示偶数个值,其中一个值为零。这意味着64位类型可以表示的正值的数量与它可以表示的负值的数量不同(或多或少)。如果jlong表示不同于long long的值范围(例如jlong表示范围-92233720368547758079223372036854775808,而long long表示-9223372036854775808 1}}到9223372036854775807)然后转换这些极值的结果可能会给出未定义的行为。

简而言之,无法保证long long能够代表与jlong完全相同的值范围。实际上,你会发现大多数现代目标平台都没问题。然而,对于一些较旧的系统而言并非如此,并且(理论上至少)将来可能会再次发生变化。

如果您能保证(例如通过分析您的Java代码)您的jlong永远不会拥有long long可能无法代表的某个违规极值,那么就不会有问题转换为long long。如果您可以保证(例如,通过参考每个目标系统和C ++编译器的文档)long long支持至少与jlong相同的值范围,那么也没有问题。

使用C ++流(每种标准类型都有重载插入运算符)比使用C I / O(依赖于您正确使用格式字符串)打印效果更好。