在另一个源文件中调用JNI C函数

时间:2018-12-05 02:31:53

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

我正在尝试从JNI native-lib.cpp文件调用C函数foo()。 foo()在foo.h中声明,并在foo.c中定义。 native-lib.cpp已经包含“ foo.h”,因此Android Studio似乎可以识别该功能存在,但是在构建时,出现以下错误:

error: undefined reference to 'foo(unsigned char const*, unsigned int*, int)'

foo()在foo.h中声明为这样:

void foo(const unsigned char key[], unsigned int w[], int keysize);
在本地lib.cpp中调用

foo()如下:

static unsigned char byteArray[32];
unsigned int intArray[64];
foo(byteArray, intArray, 256);

我错过了什么吗?为什么会出现错误?

我还注意到,当我打开foo.c时,Android Studio通知我:“此文件不属于项目的一部分。请将其包含在适当的构建文件中(build.gradle,CMakeLists.txt或Android.mk等等)并同步项目。”我该怎么办?

1 个答案:

答案 0 :(得分:1)

可能的问题是链接器将您的foo()函数识别为C++函数,而不是C函数。

由于C++函数可以重载,因此C ++编译器会“混用”该名称,以便链接程序具有该函数的唯一键。遇到foo.h的任何C ++模块都将假定该函数为C ++函数,因此名称修饰将在函数名称上进行。

例如,在编译后的目标代码中,整齐的名称可能看起来像这样:

foo@ucharp@uintp@int

(每个品牌的C ++编译器都有其自己的命名方案)。

另一方面,当C编译器遇到foo.h时,编译后的目标代码会产生一个符号,或多或少地表示一个“未修饰的” foo名称:

foo_foo

因此,现在在链接时,由于您从C ++代码调用了foo函数,因此链接程序将尝试查找错误的版本,并且由于没有名为foo的C ++函数,因此您可以链接器错误。

因此,基本上,您的foo.h标头或它的用法必须很聪明,并且适用于C模块 C ++模块,其中C ++模块知道{{ 1}}是指foo函数,因此不会破坏名称。


一种方法是将C更改为此:

foo.h

因此,基本上,当#ifdef __cplusplus extern "C" { #endif void foo(const unsigned char key[], unsigned int w[], int keysize); #ifdef __cplusplus } #endif 编译器看到标头时,C不存在。对于C ++模块,定义了__cplusplus,因此__cplusplus生效,因此C ++模块将extern "C"识别为foo()函数。

如果您无法更改C,则可以在C ++模块中将其与foo.h包围起来

extern "C"

See this on more information of __cplusplus