乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      關于最近用Golang和Qt混寫程序所遇到的坑

       quasiceo 2016-11-20

      關于最近用Golang和Qt混寫程序所遇到的坑

      先說 Mac os 下面吧

      一路上順風順水。

      總結(jié)了一下,CGO所使用的原理,在Go里面調(diào)用C的程序

      其實就是使用了C++的一個特性,extern

      1. // 網(wǎng)上是這樣解釋的
      2. extern可置于變量或者函數(shù)前,以表示變量或者函數(shù)的定義在別的文件中
      3. 提示編譯器遇到此變量和函數(shù)時在其他模塊中尋找其定義。

      當你對一個函數(shù) extern 聲明后,這個函數(shù)你就可以使用了,但是其實它并不存在,需要Go去生成

      // Go 生成有個前地,就是在這個函數(shù)上面加一行(//export cgo_connect),cgo_connect 就是函數(shù)名

      但是當使用的時候,其實Go已經(jīng)生成好了,編譯到程序里面,所以運行的就是所以 Cgo 的程序

      1. // 可以通過一個命令來看 Go 中間做了什么
      2. go tool cgo xxx.go
      3. // 這 xxx.go 里面要寫的就是下面這些C與Go的混合代碼
      4. /*
      5. // 這里看到 extern 了把,使用這個的函數(shù),只有三個地方存在
      6. // 一,注釋內(nèi)
      7. // 二,Go 內(nèi)用 //export drv_cgo_connect 實現(xiàn)的
      8. // 三,在 C 里面實現(xiàn)的(可能是文件,也可能是庫)
      9. extern void drv_cgo_connect(int (*)(void *, int));
      10. static void init_callback()
      11. {
      12. extern int cgo_connect(void *, int);
      13. drv_cgo_connect(&cgo_connect);
      14. }
      15. */
      16. // #include <stdio.h>
      17. // #include <stdlib.h>
      18. // #cgo LDFLAGS: -L./ -lexamples // 庫內(nèi)有一切,不僅調(diào)用,還可以互訪
      19. import "C"
      20. import "unsafe"

      21. func start() {
      22. C.init_callback()
      23. }

      24. // 這里就是生成了一個 C 的 cgo_connect 函數(shù)
      25. // 想要在 C 中使用這個函數(shù),就需要在 C 里面 extern int cgo_connect(...) 才可以.
      26. //export cgo_connect
      27. func cgo_connect(_content unsafe.Pointer, _size C.int) C.int {
      28. device := string(C.GoBytes(_content, _size))
      29. log.Println("Go->", device)
      30. if err := StaticConn.Connect(device); err != nil {
      31. return C.int(0)
      32. }
      33. return C.int(1)
      34. }

      這樣一來,你就可以在 Go 里面調(diào)用 C 里面實現(xiàn)的函數(shù)

      同樣原理,如果 C 想要調(diào)用 Go 的函數(shù),相同方法,只是把 extern 調(diào)換一下!


      上面簡單的了解了一下,CGO 原理,現(xiàn)在說一下具體情況,比如 QT 這樣龐大的程序

      對于 QT 這樣的大程序,而且涉及到 QMake 編譯,所以使用 CGO 本身混編(.go,.c.,.h)就沒戲了

      所以怎么辦呢,這位同學說對了,就是這樣,使用庫(windows是dll)(linux是so)(mac是dylib)

      將 QT 的 .Pro 文件改一下 TEMPLATE = lib 這樣就會生成庫文件

      但是上面的同學問了,庫文件能被Go調(diào)用,那庫文件怎么調(diào)用Go呢

      問題就來了,我試驗了無數(shù)次??樱?,坑!

      你想到了,extern 沒錯,但是 extern 的函數(shù)需要在本庫中找到實現(xiàn)的函數(shù)

      對于Cgo里面,你沒有實現(xiàn)是因為你設置了 //export 所以 Go 就幫你做了

      所以怎么辦,對了,你想到,go tool cgo 把 C 編譯出來,導入到 QT 中不就了。

      錯,大錯特錯,編譯出來的文件,不完整,可遠觀,不可近玩嫣!

      我試的時候雖然能編譯過,但是 Go 轉(zhuǎn) C 的函數(shù)根本沒運行

      這樣一來,樓上的同學哭了,那怎么辦啊。

      當當當當~!在這里用到了 C++ 的另外一個關鍵字 inline 隆重出馬

      1. // 網(wǎng)上這樣介紹的
      2. inline關鍵字用來定義一個類的內(nèi)聯(lián)函數(shù),引入它的主要原因是用它替代C中表達式形式的宏定義。

      也就是說,你在C庫中用inline定義一個空函數(shù),然后使用TA,然后在Go里面用//export 定義一個同名函數(shù)。

      這樣一來,C里面就使用的不是inline定義的函數(shù),而是你Go里面的函數(shù)了,天哪,太簡單,太方便了。


      再說 Windows 這個坑吧

      當你 Mac 或者 Linux 按照上面方法,寫完了,你可能興高采烈的跑去 windows 編譯

      當你 費了 九牛二虎之力,把環(huán)境編譯好了,之后呢,編譯唄,坑坑坑,恭喜,你又掉坑里了。

      這個問題,我找啊找,查啊查,費了就牛二老之力,找到了問題了。

      1. 問題就是 inline // 網(wǎng)上是這樣說的
      2. inline說明對編譯器來說只是一種建議,編譯器可以選擇忽略這個建議。
      3. 比如,你將一個長達1000多行的函數(shù)指定為inline,編譯器就會忽略這個inline,將這個函數(shù)還原成普通函數(shù)。

      天哪,看編譯器心情嗎,在 Mac 里面就用 Go 里面 原始函數(shù),在 Windows 下面就選擇了,inline 定義的空函數(shù),這可怎么辦啊。

      網(wǎng)上一頓亂找,什么,強制 inline ,編譯器不優(yōu)化,一頓亂找,搞不定啊。

      后來聽說,windows 對 dll 有特殊限制,有些 關鍵字無法傳遞,比如 inline ,所以,唉?。。?,沒辦法.

      既然不用 inline 也就不能用 extern 因為 只有加了 extern inline 的函數(shù)才變成實際存在的,如果去掉 inline

      編譯器會一直提示你,沒有找到,沒有找到,沒有找到。啊啊啊啊啊啊??!


      找啊找,查啊查,坑啊坑??戳艘恍﹦e人的代碼,涉及到的太少,幾乎沒有

      翻了一下 liteide 的代碼,哈哈,看到曙光了,怎么辦呢

      是怎么處理的呢,比較復雜,但是可行

      就是在 Cgo 里面自己調(diào)用自己的函數(shù),然后 CGo 的方法,把函數(shù)指針傳到庫里去,在庫里面搞個全局保存一下.

      1. /*
      2. extern void drv_cgo_connect(int (*)(void *, int));
      3. static void init_callback()
      4. {
      5. extern int cgo_connect(void *, int);
      6. drv_cgo_connect(&cgo_connect);
      7. }
      8. */
      9. // #include <stdio.h>
      10. // #include <stdlib.h>
      11. // #cgo LDFLAGS: -L./ -lexamples
      12. import "C"
      13. import "unsafe"

      14. func start() {
      15. C.init_callback()
      16. }

      17. //export cgo_connect
      18. func cgo_connect(_content unsafe.Pointer, _size C.int) C.int {
      19. device := string(C.GoBytes(_content, _size))
      20. log.Println("Go->", device)
      21. if err := StaticConn.Connect(device); err != nil {
      22. return C.int(0)
      23. }
      24. return C.int(1)
      25. }

      26. // 在 C 里面是這樣

      27. typedef int (*COMMAND_CGO_CONNECT_FUNCTION)(void *, int);

      28. typedef int (*COMMAND_CGO_CHECKCONN_FUNCTION)();

      29. COMMAND_CGO_CONNECT_FUNCTION cgo_connect;

      30. COMMAND_CGO_CHECKCONN_FUNCTION cgo_checkconn;

      31. extern "C" void drv_cgo_connect(int (*_a)(void *, int))
      32. {
      33. cgo_connect = _a;
      34. }

      35. extern "C" void drv_cgo_checkconn(int (*_a)())
      36. {
      37. cgo_checkconn = _a;
      38. }

      這樣一來,問題解決了,但是復雜了一些,對 Cgo 減10分.


      補充,當 windows 運行的時候 會顯示 DOS 窗口,怎么辦呢

      1. go build -ldflags -H=windowsgui
      2. go build -ldflags -H=windowsgui XXX.go

      再次補充:

      1. // 可以把函數(shù)當指針傳,這樣就不需要那么多的 drv_cgo_xxx
      2. /*
      3. extern void cgo_init();
      4. extern int cgo_start();
      5. extern void cgo_callback(void *);
      6. extern void drv_cgo_callback(int, void*);
      7. extern void drv_cgo_callback_2(int, void*);
      8. static void init_callback()
      9. {
      10. int _cgo_connect = 1;
      11. int _cgo_checkconn = 2;
      12. int _cgo_disconn = 3;
      13. int _cgo_command = 4;
      14. int _cgo_shortcuts = 5;
      15. int _cgo_message = 6;
      16. extern int cgo_connect(void *, int);
      17. extern int cgo_checkconn();
      18. extern void cgo_disconn();
      19. extern void cgo_command(void *, int);
      20. extern void cgo_shortcuts(void *, int);
      21. extern void * cgo_message();
      22. drv_cgo_callback_2(_cgo_connect, &cgo_connect);
      23. drv_cgo_callback_2(_cgo_checkconn, &cgo_checkconn);
      24. drv_cgo_callback(_cgo_checkconn, &cgo_checkconn);
      25. drv_cgo_callback(_cgo_disconn, &cgo_disconn);
      26. drv_cgo_callback(_cgo_command, &cgo_command);
      27. drv_cgo_callback(_cgo_shortcuts, &cgo_shortcuts);
      28. drv_cgo_callback(_cgo_message, &cgo_message);
      29. }
      30. */

      31. typedef int (*COMMAND_CGO_CONNECT_FUNCTION)(void *, int);

      32. typedef int (*COMMAND_CGO_CHECKCONN_FUNCTION)();

      33. static COMMAND_CGO_CONNECT_FUNCTION cgo_connect = 0;

      34. static COMMAND_CGO_CHECKCONN_FUNCTION cgo_checkconn = 0;

      35. extern "C" void drv_cgo_callback_2(int _a, void * _b)
      36. {
      37. /*
      38. int _cgo_connect = 1;
      39. int _cgo_checkconn = 2;
      40. */
      41. switch (_a) {
      42. case 1:
      43. cgo_connect = (COMMAND_CGO_CONNECT_FUNCTION)_b;
      44. break;
      45. case 2:
      46. cgo_checkconn = (COMMAND_CGO_CHECKCONN_FUNCTION)_b;
      47. break;
      48. }
      49. }



        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多