Передача указателя из C в Java становится NULL - PullRequest
3 голосов
/ 19 июля 2011

Я работаю над приложением Android для x86, которое требует некоторой интеграции с C. Я использовал swig / JNI, чтобы сделать трюк, и в большинстве случаев все шло гладко. Однако указатели дают мне некоторые ошибки.

Моя проблема в том, что я могу успешно ссылаться на переменные адреса в эмуляторе (ARM), но на устройстве (x86) дела идут не так хорошо.

Используя пример из этой ссылки , я обнаружил, что адрес любой выделенной переменной в C становится NULL, как только этот адрес переходит к Java. Например ...

Сгенерированный Swig JNI:

SWIGEXPORT jlong JNICALL Java_exampleJNI_new_1intp(JNIEnv *jenv, jclass jcls) {
  jlong jresult = 0 ;
  int *result = 0 ;
  (void)jenv;
  (void)jcls;
  result = (int *)new_intp();
  LOGI("Result is %x", result);
  *(int **)&jresult = result; 
  LOGI("JResult is %x", jresult);
  return jresult;
}

Исходный файл, содержащий new_intp ():

static int *new_intp() {
  return (int *) calloc(1,sizeof(int));
}

У меня есть операторы print, проверяющие значение адреса в том виде, как оно исходит из C и переходит на Java. В new_intp () новой переменной присваивается красивый адрес, но как только это значение возвращается в JNI и преобразуется в jlong, оно превращается в NULL.

Другими словами, *(int **)&jresult = result; приводит к тому, что jresult равен 0.

Почему это происходит? Есть ли какая-то особенность x86, которая запрещает JNI работать с указателями? Или потому, что я тестирую его на физическом устройстве, а не на эмуляторе?

Привет

Ответы [ 2 ]

11 голосов
/ 22 сентября 2011

На самом деле, это псевдоним указателя . SWIG использует старые методы указателя C, которые не работают в новых GCC, когда включена оптимизация. Похоронен в документах SWIG конкретно говорит, что делать :

Важно

Если вы собираетесь использовать оптимизации, включенные с помощью gcc (например, -O2), убедитесь, что вы также компилируете с -fno-strict-aliasing. Оптимизация GCC стала более агрессивной, начиная с gcc-4.0 и приведет к коду, который терпит неудачу со строгими оптимизациями алиасинга включенный. Подробности смотрите в разделе C / C ++ to Java .

2 голосов
/ 20 июля 2011

Мне кажется, что это может быть проблема с порядком байтов.

*(int **)&jresult = result; 

Если int равно 32 битам, а jresult равно 64 битам, то для архитектуры с прямым порядком байтов это может датьнеожиданные результаты.

&jresult - это указатель на 64-разрядное значение, поэтому, если вы приведете его к указателю на 32-разрядное значение, то вы указываете на нижний адрес двух составляющих 32-немного слов.В системе с прямым порядком байтов это будет самое важное слово.Таким образом, после записи 32-разрядного слова в самый значимый конец 64-разрядного значения вы получите 64-разрядное значение, которое в 2 ^ 32 раза больше, чем вы ожидаете.

Если ваш LOGIcall обрабатывает параметр как 32-битный тип int и неявно преобразует его из 64-битного значения, а затем возвращает 0.

Можете ли вы увидеть, работает ли он вместо этого?

jresult = (jlong) result; 
...