亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何使用 CGo 為標準庫調用 C++ 變量

如何使用 CGo 為標準庫調用 C++ 變量

Go
慕斯王 2023-01-03 10:13:55
我正在嘗試使用 cgo 從 C++ 代碼中獲取變量值。對于以.hall 結尾的庫工作正常,但對于,等庫<iostream>,我收到以下錯誤:<map><string>fatal error: iostream: No such file or directory    4 | #include <iostream>      |          ^~~~~~~~~~在我的代碼下面:package main/*#cgo LDFLAGS: -lc++#include <iostream>std::string plus() {    return "Hello World!\n";}*/import "C"import "fmt"func main() {    a := Plus_go()    fmt.Println(a)}func Plus_go() string {    return C.plus()}我添加了這個標志,因為我在https://stackoverflow.com/a/41615301/15024997#cgo LDFLAGS: -lc++的 stackoverflow 上的一個答案中看到了這個建議。我正在使用 VS Code(不是 VS Studio)、Windows 10、Go 1.18(最新版本)。我運行了以下命令go tool cgo -debug-gcc mycode.go來跟蹤編譯器的執行和輸出:$ gcc -E -dM -xc -m64 - <<EOF#line 1 "cgo-builtin-prolog"#include <stddef.h> /* for ptrdiff_t and size_t below *//* Define intgo when compiling with GCC.  */typedef ptrdiff_t intgo;#define GO_CGO_GOSTRING_TYPEDEFtypedef struct { const char *p; intgo n; } _GoString_;typedef struct { char *p; intgo n; intgo c; } _GoBytes_;_GoString_ GoString(char *p);_GoString_ GoStringN(char *p, int l);_GoBytes_ GoBytes(void *p, int n);char *CString(_GoString_);void *CBytes(_GoBytes_);void *_CMalloc(size_t);__attribute__ ((unused))static size_t _GoStringLen(_GoString_ s) { return (size_t)s.n; }__attribute__ ((unused))static const char *_GoStringPtr(_GoString_ s) { return s.p; }#line 3 "C:\\Users\\Home\\OneDrive\\Desktop\\DevicesC++\\devices.go"#include <iostream>std::string plus() {    return "Hello World!\n";}#line 1 "cgo-generated-wrapper"EOFC:\Users\Home\OneDrive\Desktop\DevicesC++\devices.go:5:10: fatal error: iostream: No such file or directory    5 | #include <iostream>      |          ^~~~~~~~~~compilation terminated.C:\Users\Home\OneDrive\Desktop\DevicesC++\devices.go:5:10: fatal error: iostream: No such file or directory    5 | #include <iostream>      |          ^~~~~~~~~~compilation terminated.
查看完整描述

1 回答

?
侃侃無極

TA貢獻2051條經驗 獲得超10個贊

CGo 允許您將 Go 代碼鏈接到實現 C 風格外部函數接口的代碼。這并不意味著您可以將任意語言代碼固定到位。


讓我們從第一個問題開始,即import "C"您的一個 Go 文件中的行必須僅包含其上方的 C 代碼。那是:


/*

#include <stdlib.h>

extern char *cstyle_plus();

*/

可以,但是:


/*

#include <stdlib.h>

extern std::string *plus();

*/

不是,您也不能#include在這里使用任何 C++ 標頭。為了稍微簡化事情,這里的注釋實際上被剪掉并提供給C 編譯器。如果它不是有效的 C,它就不會編譯。


如果你想包含 C++ 代碼,你可以,但你必須將它放在一個或多個單獨的文件中(從技術上講,C 或 C++ 術語中的“翻譯單元”)。然后 CGo 將該文件編譯為目標代碼。


然而,下一個問題是目標代碼必須符合CGo 實現的 C外部函數接口。這意味著您的 C++ 代碼必須返回 C 類型(和/或接收此類類型作為參數)。由于std::string不是 C 字符串,您實際上不能直接返回它。


它不是很有效(并且存在一些解決此問題的嘗試),但處理此問題的常用方法是讓 C 函數返回 C 風格的“char *”或“const char *”字符串。如果字符串本身具有非靜態持續時間——就像你的那樣——你必須malloc在這里使用,特別是C malloc(std::malloc可能是不可互操作的)。


函數本身也必須可以從C 代碼調用。這意味著我們需要使用extern "C"它。


因此,我們的plus.cpp文件(或任何你想稱呼它的東西)可能會這樣讀:


#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);

}

}

然后我們可以使用這個從 Go 中調用它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)

}

添加一個 trivialgo.mod和 building,生成的代碼運行;雙換行是因為C字符串里面有一個換行符,加fmt.Println了一個換行符:


$ go build

$ ./cgo_cpp

Hello World!


這段代碼有點草率:應該malloc失敗,它返回 NULL,并將C.GoString其變成一個空字符串。然而,真正的代碼應該盡量避免這種愚蠢的分配和釋放序列:例如,我們可能知道字符串長度,或者有一個static不需要這種愚蠢的字符串malloc。


查看完整回答
反對 回復 2023-01-03
  • 1 回答
  • 0 關注
  • 344 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號