我在C ++中遇到了问题。
我创建了一个名为execute
的函数int* execute(int tab[], int n)
{
for (int i = 0; i<n; i++)
{
for (int j = 0; j < n-1; j++)
{
if (tab[j] > tab[j+1])
{
int tmp = tab[j];
tab[j] = tab[j+1];
tab[j+1] = tmp;
}
}
}
return tab;
}
所以,这是简单的BubbleSort功能。我在文件BubbleSortAlgorithm.cpp中有这个函数。
因此,在我的程序的主要功能中,我检查libBubbleSortAlgorithm.so是否存在。如果没有,那么我必须创建这个lib。这个lib是通过popen创建的。所以我最终得到了文件libBubbleSortAlgorithm.so。如果我运行命令
nm libBubbleSortAlgorithm.so | c++filt
然后我得到这样的东西。
0000000000000ed0 T execute(int*, int)
U dyld_stub_binder
我认为这没关系。所以,接下来在主程序中,我用dlopen在我的程序中加载这个.so文件并像这样调用这个函数
void *handle = dlopen(buff, RTLD_LAZY);
if (handle)
{
execute = dlsym(handle, "execute");
int tab[5] = { 5, 2, 4, 7, 1 };
int x = 5;
execute(tab, x);
}
但在主要之前我也写过这个
#ifdef __cplusplus
extern "C" {
#endif
void (*execute)(int*, int);
#ifdef __cplusplus
}
#endif
所以,在Xcode7中,我收到此错误: /Users/Tadej/Documents/Development/ALGatorC_final/ALGatorC/ALGatorC/main.cpp:96:49:分配给&#39; void(*)(int *,int)&#39;来自不兼容的类型&#39; void *&#39;
提前感谢您的帮助。
此致 golobich
编辑:我改变了这样的代码:
#ifdef __cplusplus
extern "C" {
#endif
int* (*execute)(int*, int);
#ifdef __cplusplus
}
#endif
execute = (int*(*)(int*, int))dlsym(handle, "execute");
int tab[5] = { 5, 2, 4, 7, 1 };
int x = 5;
int *xs = execute(tab, x);
for (int i = 0; i<5; i++)
{
std::cout << xs[i] << ", ";
}
所以,现在,我在运行时遇到了问题。在执行(tab,x)时,Xcode会抱怨并说出:EXC_BAD_ACCESS(code = 1,address = 0x0)。所以,问题是execute是NULL。有帮助吗? :)
答案 0 :(得分:2)
您可以安全地投射结果。
dlsym只返回一个(函数)指针,但不知道(也不能)知道函数的实际签名。只有客户代码(您的)才能知道。
Cast可以这样做:
typedef int *(*execute_t)(int, int) ;
...
execute = (execute_t *)dlsym(handle, "execute");
请记住@molbdnilo所说的关于被称为'extern“C”的函数的内容。这必须在库代码中完成,而不是在客户端
extern "C" int* execute(int tab[], int n)
{
for (int i = 0; i<n; i++)
{
....
答案 1 :(得分:2)
库中的函数未使用 final Intent intent = new Intent(Intent.ACTION_VIEW);
String extension = fileName.substring(fileName.lastIndexOf('.'));
intent.setDataAndType(Uri.fromFile(new File("fileName")), "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_SINGLE_TOP);
if (!this.context.getPackageManager()
.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY).isEmpty()) {
startActivity(intent);
finish();
}
链接进行编译,因此该名称在库中具有C ++名称更改。
因此,extern "C"
找不到名称“execute”并返回空指针。
在库中添加dlsym
,或extern "C"
实际符号,如dlsym
所示,不用通过nm
管道输出。<登记/>
或者用C代码构建你的库。
答案 2 :(得分:0)
我遇到了同样的问题,但是我没有使用外部“ C”关键字进行了以下操作。假设我们在 Users / you / Desktop / FooProject 中创建目录,并编写共享库 foo.cpp :
#ifndef FOO_H
#define FOO_H
int sum(int x, int y)
{
return x+y;
}
int subs( int x, int y)
{
return x-y;
}
#endif //FOO_H
我们从 foo.cpp 创建共享库:
g++ -dynamiclib foo.cpp -o libfoo.dylib
现在,我们想编写一个程序,该程序在同一目录 / Users / You / FooProject / 中获取指向我们库的函数指针。为此,我们使用 dlopen(), dlsym()和 dlclose()函数。
由于C ++名称处理(用于函数重载),我们的函数名称将不同于我们在 foo.cpp 上编写的名称。
如果我们运行 objdump -t libfoo.dylib ,我们将在我的机器上得到以下输出:
libfoo.dylib: file format Mach-O 64-bit x86-64
SYMBOL TABLE:
0000000000000f80 g F __TEXT,__text __Z3sumii
0000000000000fa0 g F __TEXT,__text __Z4subsii
0000000000000000 *UND* dyld_stub_binder
这是很棘手的事情。请注意名称 __ Z3sumii 和 __ Z4subsii 前的两个下划线。我们要提取的函数的实际名称只有一个下划线,而不是两个。函数的名称为 _Z3sumii 和 _Z4subsii ,只有一个下划线。
如果您尝试提取 dlsym()上的函数,并用两个下划线或原始名称传递名称,则它将返回 NULL 。
错误:
int (*sum)(int, int);
sum = dlsym(foo_lib_handle,"__Z3sumii");//two underscores and no casting
or
int (*sum)(int, int);
sum = dlsym(foo_lib_handle,"sum"); //the name demangled and no casting
正确:
int (*sum)(int, int);
sum = ( int(*)(int, int) ) dlsym(foo_lib_handle,"_Z3sumii");
由于dlsym返回一个void指针,并且预期的signatura不同,因此我们需要对其进行适当的强制转换。
现在,我们知道了所需的名称。我们可以编写代码来提取dylib的函数指针,称为 pullout.cpp :
#include <dlfcn.h>
#include <iostream>
int main( )
{
//function pointers for the pulled functions
int (*sum)(int, int);
int (*subs)(int, int);
// open the shared library
void* foo_lib_handle = dlopen("libfoo.dylib", RTLD_LAZY | RTLD_GLOBAL);
if(!foo_lib_handle)
{
std::cout << "problemo loading dylib" << std::endl;
return 1;
}
//notice the casting and the name "_Z3sumii" instead of "__Z3sumii" and the same for subs
sum = ( int(*)(int, int) ) dlsym(foo_lib_handle,"_Z3sumii");
subs = ( int(*)(int,int ) ) dlsym(foo_lib_handle,"_Z4subsii");
if( sum == NULL || subs == NULL )
{
std::cout << "functions pointers are null" << std::endl;
return 1;
}
std::cout << "calling sum(8,8) = " << sum(8,8) << '\n';
std::cout << "calling subs(18,8) = "<< subs(18,8) <<'\n';
//close the library
dlclose(foo_lib_handle);
return 0;
}
编译 pullout.cpp :
g++ -c pullout.cpp
要链接生成的 pullout.o 文件,我们可以使用几种方法:
我们可以使用 -L 指定搜索lib的路径,以及 -l </ strong>:
g++ pullout.o -L. -lfoo -o pulloutFoo
-l </ strong>选项扩展为 -libfoo.dylib 。请务必注意,gcc的默认搜索路径为:
/usr/local/lib
/usr/lib
因此,我们需要在路径后使用 -L 选项。在我们的例子中,我们使用当前目录。
第二个选项是指定lib的完整路径和名称,因此我们不必使用te -L 和 -l </ strong>选项
g++ pullout.o libfoo.dylib -o pullFoo
第三种选择,将共享库放入常见目录之一,例如 / usr / local / lib 。然后我们就可以做:
g++ pullout.o -lfoo -o pullFoo
如果我们运行它:
$ ./pullFoo
calling sum(8,8) 16
calling subs(18,8) 10
其他:
有关运行时问题,请参见dynamic libraries和macOs以及此处stakoverflow的mac os安装名称。