golang cgo 開發小結

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

工作上遇到一個需求,需要把一個C++的動態庫的功能封裝為Web介面。由於沒有C++開發經驗,C有點經驗,於是考慮了兩種方案:

  1. 封裝為PHP擴充
  2. 在Golang中使用CGO

兩種方案我都可以做,但最終決定採用第2種方案,主要考慮的因素是這個Web服務最終需要在客戶那裡進行私人化部署,採用PHP的話,部署的時候還需要Nginx、Fpm(當然也可以直接用Swoole),但是PHP代碼是明文的,雖然可以買一些商業軟體進行加密(比如Swoole Compiler)。如果直接用Golang的話,就可以直接給使用者部署一個二進位程式(需要strip掉符號資訊)就可以了,部署起來更方便。

下面將通過一個樣本程式,示範如何在Golang中通過cgo調用C++。

範例程式碼目錄:

.├── bin│   └── cgo└── src    └── cgo        ├── c_src.cpp   // 在Golang中調用的C函數定義        ├── c_src.h     // C標頭檔,聲明了哪些C函數會在Golang中使用,在main.go中包含        ├── main.go        ├── src.cpp     // C++代碼        └── src.hpp     // C++標頭檔

c_src.h 源碼:

#ifndef WRAP_CPP_H#define WRAP_CPP_H#ifdef __cplusplusextern "C" {#endif // __cplusplustypedef void* Foo;Foo FooNew();void FooDestroy(Foo f);const char* FooGetName(Foo f, int* retLen);void FooSetName(Foo f, char* name);#ifdef __cplusplus}#endif // __cplusplus#endif // WRAP_CPP_H

extern "C"作用:Combining C++ and C - how does #ifdef __cplusplus work?

c_src.cpp 源碼:

#include "src.hpp"#include "c_src.h"#include <cstring>// 返回cxxFoo對象,但轉換為void*Foo FooNew(){    cxxFoo* ret = new cxxFoo("rokety");    return (void*)ret;}void FooDestroy(Foo f){    cxxFoo* foo = (cxxFoo*)f;    delete foo;}// 封裝cxxFoo的get_name方法const char* FooGetName(Foo f, int* ret_len){    cxxFoo* foo = (cxxFoo*)f;    std::string name = foo->get_name();    *ret_len = name.length();    const char* ret_str = (const char*)malloc(*ret_len);    memcpy((void*)ret_str, name.c_str(), *ret_len);    return ret_str;}// 封裝cxxFoo的set_name方法void FooSetName(Foo f, char* name){    cxxFoo* foo = (cxxFoo*)f;    std::string _name(name, strlen(name));    foo->set_name(_name);}

c_src.cpp 可能的疑問:

  • 為何需要定義Foo?因為在C中沒有Class的概念,所以需要把C++的Class轉換為C中的資料類型
  • 為何在FooGetName中需要進行malloc和memcpy?因為name是局部變數,並且記憶體配置在棧上,當cgo調用返回後,name所佔用的記憶體會被釋放掉。

main.go 源碼:

package main// #include "c_src.h"// #include <stdlib.h>import "C"import ("fmt""unsafe")type GoFoo struct {foo C.Foo}func NewGoFoo() GoFoo {var ret GoFooret.foo = C.FooNew()return ret}func (f GoFoo) Destroy() {C.FooDestroy(f.foo)}func (f GoFoo) GetName() string {rLen := C.int(0)name := C.FooGetName(f.foo, &rLen)defer C.free(unsafe.Pointer(name))  // 必須使用C的free函數,釋放FooGetName中malloc的記憶體return C.GoStringN(name, rLen)      // 從name構造出golang的string類型值}func (f GoFoo) SetName(name string) {cname := C.CString(name)        // 將golang的string類型值轉換為c中的char*類型值,這裡會調用到c的mallocC.FooSetName(f.foo, cname)C.free(unsafe.Pointer(cname))   // 釋放上面malloc的記憶體}func main() {foo := NewGoFoo()fmt.Println(foo.GetName())foo.GetName()foo.SetName("new rokety")fmt.Println(foo.GetName())foo.Destroy()}

main.go 可能的疑問:

  • unsafe.Pointer(…)相當於把變數強轉為C中的void*類型
  • SetName中為何需要做轉換,因為name變數的記憶體是在Golang中分配的,且string類型是不可修改的,因此,需要在c中分配name所需要的記憶體,以便在FooSetName中使用
  • 需要注意的一點是import "C"上面必須緊跟// #include ...注釋

src.hpp 源碼:

#ifndef CXX_H#define CXX_H#include <string>class cxxFoo{public:    cxxFoo(std::string name);    ~cxxFoo();    std::string get_name();    void set_name(std::string name);private:    std::string name;};#endif // CXX_H

src.cpp 源碼

#include "src.hpp"#include <iostream>cxxFoo::cxxFoo(std::string name){    this->name = name;}cxxFoo::~cxxFoo(){}std::string cxxFoo::get_name(){    return this->name;}void cxxFoo::set_name(std::string name){    this->name = name;}

小結:

  • C中的資料類型會與Golang的C.xxx資料類型對應:CGO 類型(CGO Types)
  • 在C/C++中申請的記憶體,就得在C/C++中釋放
  • 對於需要連結C/C++動態庫,或加上編譯參數,可以在import "C"加上對應注釋// #cgo CFLAGS: -DPNG_DEBUG=1

參考資料:

  • How to use C++ in Go?
  • Command cgo
  • C? Go? Cgo!
  • Golang CGO編程之調用返回char*指標及長度的C函數庫
  • CGO: Go與C互操作技術(一):Go調C基本原理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.