C/C++ long 数值溢出


在写 android NDK 的时候碰到的一个小情况
比如,我声明一个 native 方法:

public static native long foo();

然后,在实现里面这样写道:

   
  struct timeval val;
  
gettimeofday(&val, NULL);
return val.tv_sec * 1000 + val.tv_usec / 1000;

当然,需要包含 sys/time.h

可是可是,收到的数是一个负数,我知道 long 默认是带符号的,可是如何跟 java 层转换呢?

java 可以轻松的使用 System.currentTimeMillis() 获取当前的毫秒时间戳,
C/C++ 要如何书写获取 ndk 返回无符号的大数呢?

c java jni C++

摸摸你的胸 11 years, 11 months ago

Android平台是arm的cpu,目前都是32bit的。
而根据源码,timeval的tv_sec是long int,有符号32bit的。

   
  106 #define __SLONGWORD_TYPE    long int
  
"bits/types.h" line 69 of 200 --34%-- col 1

50 #define __TIME_T_TYPE __SLONGWORD_TYPE
"bits/typesizes.h" 66L, 2538C

152 __STD_TYPE __TIME_T_TYPE __time_t; /* Seconds since the Epoch. */
"bits/types.h" line 115 of 200 --57%-- col 18

67 /* A time value that is accurate to the nearest
68 microsecond but also has a range of years. */
69 struct timeval
70 {
71 __time_t tv_sec; /* Seconds. */
72 __suseconds_t tv_usec; /* Microseconds. */
"bits/time.h" 75L, 2552C

有符号32bit最大可以表示68年的秒数吧,从1970年算起的到现在的秒数是不会溢出的(还有20多年就溢出了)。
但如果转化为毫秒数扩大1000倍就必然会溢出。所以自1970年的毫秒数必须使用64bit来表示。
所以溢出发生在C代码return的时候,表达式val.tv_sec * 1000已经溢出了。

就这个问题而言,可以稍稍修改一下实现,让C返回一个结构体(成员是tv_sec和tv_usec)给java(应该可以吧?java我不是太熟悉)然后在java内转换为毫秒就可以了。

蓝天下的乌鸦 answered 11 years, 11 months ago

Your Answer