使用 C 打包为 Android 的 C-shar(so)动态链库,然后使用 Fltter 的 ffi 调用。现在我实现了函数为 int 类型的相互调用,但是 string(*char)始终有问题。
将 C 程序打包为 so 动态链库,并能在 Flutter 项目上正常使用,仅 Android 即可,使用 CMake ; C 程序:
#include <stdio.h>
#include <stdlib.h>
int Hello(){
return 233;
}
char *World(){
char *r = "1234";
return r;
}
char *Test(char *str)
{
return str;
}
我自己写的 ffi 类,可供参考:链接: https://pan.baidu.com/s/1z-ooHzgkbM2SkzWrkJs4eA 提取码: 9awt
我打包的动态链库,如果相信没问题可以直接用:链接: https://pan.baidu.com/s/16lZ8NwUexXJ3rpFcCxZwLw 提取码: c8s7
打包命令:
D:\Desktop\test>E:\android-ndk-r22-windows-x86_64\android-ndk-r22\toolchains\llvm\prebuilt\windows-x86_64\bin\aarch64-linux-android24-clang -shared -o mylib.so -Xlinker -soname=mylib.so -lm mylib.c
D:\Desktop\test>E:\android-ndk-r22-windows-x86_64\android-ndk-r22\toolchains\llvm\prebuilt\windows-x86_64\bin\aarch64-linux-android-nm.exe ./mylib.so
00000000000014f4 t __atexit_handler_wrapper
U __cxa_atexit
U __cxa_finalize
00000000000025b0 d __dso_handle
00000000000025b0 d __dso_handle_const
00000000000014ec t __emutls_unregister_key
00000000000004dc r __FRAME_END__
00000000000014e0 t __on_dlclose
00000000000014f0 t __on_dlclose_late
U __register_atfork
00000000000025c8 d _DYNAMIC
0000000000001500 t atexit
0000000000001528 T Hello
0000000000000290 r ndk_build_number
0000000000000250 r ndk_version
0000000000000238 r note_android_ident
000000000000024c r note_data
00000000000002d0 r note_end
0000000000000244 r note_name
000000000000151c t pthread_atfork
000000000000154c T Test
0000000000001530 T World
1
kosgug 2021-02-26 11:02:42 +08:00
建议把悬赏金额调低
|
2
liprais 2021-02-26 11:03:04 +08:00
单纯的提问都比你这 99.9 好
|
3
20015jjw 2021-02-26 11:05:37 +08:00 via Android 1
这就跟求包养
一个月只要两包泡面一样... |
4
pekki 2021-02-26 11:10:07 +08:00
你是不是把程序员的时薪想的太低了。。。
|
5
youthfire 2021-02-26 11:14:28 +08:00 via iPhone 4
传说中的伤害性不大,侮辱性极强
|
6
heyjei 2021-02-26 11:17:15 +08:00 4
一杯星巴克或者一杯瑞幸的外卖都比你这个 99.9 更有吸引力啊
|
7
hanxiV2EX 2021-02-26 11:17:16 +08:00 2
试试这样?记得 free 它
char *World(){ char *tmp = "1234"; char *r = malloc(strlen(tmp)+1); strcpy(r, tmp); return r; } void FreeWorld(char *){ free(r) } |
8
wzb0909 2021-02-26 11:17:51 +08:00
99 元让人看完你的字都不够啊
|
9
hanxiV2EX 2021-02-26 11:23:03 +08:00 1
建议 @phpIsNumberOne 重新学习 C 语言吧,内存没搞清楚写出来的东西会挂的。
|
10
danhahaha 2021-02-26 11:27:19 +08:00
建议改成 100.99 或者 0.1K 这样看起来比较多
|
11
vone 2021-02-26 11:30:14 +08:00
没八百这活干不了。
|
12
hanssx 2021-02-26 11:30:48 +08:00 3
99.9 不少了,而且题主提问的方式挺正规的吧?
话说我记得*和后面的之间是不是加个空格更 c ? |
13
mm163 2021-02-26 11:40:04 +08:00
Flutter 没用过,不清楚。
java 虚拟环境与 c 不是一个空间的,字符串处理应该使用 jni,不能直接返回指针。 |
14
pkookp8 2021-02-26 11:50:06 +08:00 via Android
我觉得需要开辟一块共享内存或者普通内存用来操作字符串。world 的 1234 是在字符常量区,可读不可写。test 的内存不知道哪来的,不知道可不可读写
char*不行 int 行,显然是内存问题。但是不懂 flutter,无能为力。试试对入参或出参进行申请内存,使用后释放。或者 socket 交互 |
15
anonydmer 2021-02-26 11:51:38 +08:00
亲,你这样用 C 返回字符串是不行的哦,内存管理错了
|
16
hantsy 2021-02-26 11:53:19 +08:00
9 。9 包邮
|
17
Chenamy2017 2021-02-26 12:48:54 +08:00
好好学学 C 语言吧,指针内存什么的。
你这个 World 函数返回的指针有问题。 |
18
phpIsNumberOne OP |
19
wangjunling 2021-02-26 14:02:44 +08:00
还不如直接求帮助, 99 悬赏真是侮辱程序员这个行业呀, 理解问题, 解决问题, 至少你的来个三位数呀, 999 或许真有人接
|
20
hanxiV2EX 2021-02-26 14:10:09 +08:00
楼主提问表述确实很清楚,有经验的一眼也就能看到问题所在。然后提供的资料也还全面,这样的提问还是值得称赞的。
|
21
oxromantic 2021-02-26 14:27:41 +08:00 2
楼上一群冷嘲热讽的不知道有没有认真看代码, 至少楼主的例子我用 flutter 跑了下是可以传到 flutter 端的
楼主的例子是 literals string, 本来就不需要栈上分配内存, 直接 return 又如何? 不知道楼主 flutter 端是怎么写的, 至少我是这样可以取到的: #include <stdint.h> #include <string.h> extern "C" __attribute__((visibility("default"))) __attribute__((used)) char* native_add(int32_t x, int32_t y) { return "12345"; } final Pointer<Utf8> Function(int x, int y) nativeAdd = nativeAddLib .lookup<NativeFunction<Pointer<Utf8> Function(Int32, Int32)>>( "native_add") .asFunction(); Text('Running on: $_platformVersion ${Utf8.fromUtf8(nativeAdd(3, 3))}\n') |
22
Visitor233 2021-02-26 14:31:24 +08:00
@hanxiV2EX 确实,学习了。
|
23
Anshi 2021-02-26 14:32:51 +08:00 4
悬赏 99.9 为什么会收到冷嘲热讽,是属于一个文化界限问题,要么一杯咖啡,对方当交个朋友,而选中帮你,要么完全不提供回馈,直接真诚提问,对方这是公益性质的帮你,如果选择一个实际的数字量化,那就需要好好讨论,帮你这个事情变得复杂,它到底值多少钱,多了,显得势力,少了,不划算,变成了人性的问题。
|
24
Ritter 2021-02-26 15:14:23 +08:00
100 块不少了 可惜我不会
|
25
NasirQ 2021-02-26 15:31:39 +08:00
抛开其他,我觉得楼主出价有问题。首先所谓 "99.9" "9.9" 这样子定价,是商家为了满足顾客的省钱心里做的定价策略。然而楼主是在寻求技术支持。这里建议改为 0.1k 或者 0.1011k,这样二进制形式的数字更能吸引人 [dog]
|
26
daoyouma 2021-02-26 15:47:35 +08:00
10 分钟能解答 我不介意 关键 我不会
|
27
yolee599 2021-02-26 20:34:54 +08:00 via Android
char *r = "1234"; 要改成 const char *r = "1234";
|
29
aheadlead 2021-02-26 21:00:48 +08:00
………………………楼上这
我来回答一下吧。楼主你在 World() 里定义的变量 char *r 是在 World() 这次函数调用的栈帧里的。 World() 函数返回后,栈帧弹出,char *r 本身所占据的 8 字节内存就不应该访问了。 虽然你仍然有可能能访问到,但这属于 undefined behavior 。 我对 Flutter 一无所知,但有可能是就是你访问了不该访问的内存(比如提示 memory access violation 、segmentation fault 之类的)。 至于你说 Test() 函数也会闪退。Test() 函数本身没有任何问题(只是没啥意义),可能和你的用法有关。楼主要是不嫌麻烦的话,把代码放到 github 或者 gist/pastebin 上,我可以一看。 |
30
aheadlead 2021-02-26 21:04:23 +08:00
补充一下,char *r 所指向的内存是在 rodata 段,这块区域的内存可以随意访问。
导致访问出错的不是 r 指向的内存,而是访问 r 本身。 FYR: https://en.wikipedia.org/wiki/Data_segment |
31
aheadlead 2021-02-26 21:08:22 +08:00
|
32
hanssx 2021-02-27 09:37:13 +08:00
@aheadlead 请教个问题,我对 c 语言也不熟,我 World()函数返回的应该是"1234"的内存地址吧?"1234"是在堆上分配的吗?如果是的话,World()函数返回值应该还能索引到"1234"这块内存吧?
|
33
aheadlead 2021-02-27 09:46:58 +08:00
@hanssx #31 你这么一说还真是。。。看来好几年没写 C 还犯错了,糗大了
你说的是正确的,昨天我发的那个代码还多此一举了,抱歉浪费各位时间。 准确的说,楼主位的代码是不会造成我说的那种内存错误。楼主可以抓个 bugreport 看下 native 的 log 是什么。 |
34
realpg 2021-02-27 11:11:31 +08:00
提问良好,字多并不啰嗦,值得鼓励
|
36
cz5424 2021-02-27 11:51:32 +08:00 via iPhone
建议楼主看一下 C 语言的指针部分,函数内分配的内存不要再返回出去,容易内存泄露
|
37
caiyue1993 2021-02-27 14:30:06 +08:00
阴阳怪气的人真多啊,“请尽量让自己的恢复能够对别人有帮助”
|
38
taogen 2021-02-27 17:47:18 +08:00
|
39
phpIsNumberOne OP 找到问题了,主要是我更新代码后使用得是热重载(Hot reload),和想象的不太一样,so 文件好像并没有更新,致使我写了正确的代码也没有正确的反馈;将 APP 卸载重新编译即可。
至于 C 内存的问题,并没有考虑那么多,只想先跑通再说;而且我实际也不是用的 C,而是用的 go(CGO);使用 C 尝试就是因为没有给我正常的反馈,还以为是 CGO 的问题。 再补充两点: 动态库的名称应该以 lib 开头,否则项目以 release 运行时会找不到; go 函数中不能写 defer C.free(unsafe.Pointer(r))释放内存,应该 dart 取到值后再释放。 |
40
phpIsNumberOne OP |