1 回答

TA貢獻(xiàn)2051條經(jīng)驗(yàn) 獲得超10個(gè)贊
CGo 允許您將 Go 代碼鏈接到實(shí)現(xiàn) C 風(fēng)格外部函數(shù)接口的代碼。這并不意味著您可以將任意語言代碼固定到位。
讓我們從第一個(gè)問題開始,即import "C"您的一個(gè) Go 文件中的行必須僅包含其上方的 C 代碼。那是:
/*
#include <stdlib.h>
extern char *cstyle_plus();
*/
可以,但是:
/*
#include <stdlib.h>
extern std::string *plus();
*/
不是,您也不能#include在這里使用任何 C++ 標(biāo)頭。為了稍微簡(jiǎn)化事情,這里的注釋實(shí)際上被剪掉并提供給C 編譯器。如果它不是有效的 C,它就不會(huì)編譯。
如果你想包含 C++ 代碼,你可以,但你必須將它放在一個(gè)或多個(gè)單獨(dú)的文件中(從技術(shù)上講,C 或 C++ 術(shù)語中的“翻譯單元”)。然后 CGo 將該文件編譯為目標(biāo)代碼。
然而,下一個(gè)問題是目標(biāo)代碼必須符合CGo 實(shí)現(xiàn)的 C外部函數(shù)接口。這意味著您的 C++ 代碼必須返回 C 類型(和/或接收此類類型作為參數(shù))。由于std::string不是 C 字符串,您實(shí)際上不能直接返回它。
它不是很有效(并且存在一些解決此問題的嘗試),但處理此問題的常用方法是讓 C 函數(shù)返回 C 風(fēng)格的“char *”或“const char *”字符串。如果字符串本身具有非靜態(tài)持續(xù)時(shí)間——就像你的那樣——你必須malloc在這里使用,特別是C malloc(std::malloc可能是不可互操作的)。
函數(shù)本身也必須可以從C 代碼調(diào)用。這意味著我們需要使用extern "C"它。
因此,我們的plus.cpp文件(或任何你想稱呼它的東西)可能會(huì)這樣讀:
#include <stdlib.h>
#include <iostream>
std::string plus() {
return "Hello World!\n";
}
extern "C" {
char *cstyle_plus() {
// Ideally we'd use strdup here, but Windows calls it _strdup
char *ret = static_cast<char *>(malloc(plus().length() + 1));
if (ret != NULL) {
strcpy(ret, plus().c_str());
}
return static_cast<char *>(ret);
}
}
然后我們可以使用這個(gè)從 Go 中調(diào)用它main.go:
package main
/*
#include <stdlib.h>
extern char *cstyle_plus();
*/
import "C"
import (
"fmt"
"unsafe"
)
func Plus_go() string {
s := C.cstyle_plus()
defer C.free(unsafe.Pointer(s))
return C.GoString(s)
}
func main() {
a := Plus_go()
fmt.Println(a)
}
添加一個(gè) trivialgo.mod和 building,生成的代碼運(yùn)行;雙換行是因?yàn)镃字符串里面有一個(gè)換行符,加fmt.Println了一個(gè)換行符:
$ go build
$ ./cgo_cpp
Hello World!
這段代碼有點(diǎn)草率:應(yīng)該malloc失敗,它返回 NULL,并將C.GoString其變成一個(gè)空字符串。然而,真正的代碼應(yīng)該盡量避免這種愚蠢的分配和釋放序列:例如,我們可能知道字符串長(zhǎng)度,或者有一個(gè)static不需要這種愚蠢的字符串malloc。
- 1 回答
- 0 關(guān)注
- 339 瀏覽
添加回答
舉報(bào)