我正在尝试从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等等)并同步项目。”我该怎么办?
答案 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"