سؤال

في الجديد اذهب اللغة، كيف يمكنني الاتصال برمز C ++؟ بمعنى آخر، كيف يمكنني التفاف فئات C ++ الخاصة بي واستخدامها في الذهاب؟

هل كانت مفيدة؟

المحلول

تحديث: لقد نجحت في ربط فئة اختبار صغيرة C ++ مع الذهاب

إذا قمت بإلغاء كود C ++ مع واجهة C يجب أن تكون قادرا على الاتصال بمكتبتك باستخدام CGO (انظر مثال GMP في $GOROOT/misc/cgo/gmp).

لست متأكدا مما إذا كانت فكرة الفصل في C ++ غير قابلة للتعبير عنها، لأنها لا تحتوي على ميراث.

إليك مثال:

لدي فئة C ++ المعرفة على النحو التالي:

// foo.hpp
class cxxFoo {
public:
  int a;
  cxxFoo(int _a):a(_a){};
  ~cxxFoo(){};
  void Bar();
};

// foo.cpp
#include <iostream>
#include "foo.hpp"
void
cxxFoo::Bar(void){
  std::cout<<this->a<<std::endl;
}

التي أريد استخدامها في الذهاب. سوف استخدم واجهة C

// foo.h
#ifdef __cplusplus
extern "C" {
#endif
  typedef void* Foo;
  Foo FooInit(void);
  void FooFree(Foo);
  void FooBar(Foo);
#ifdef __cplusplus
}
#endif

(أنا استخدم void* بدلا من بنية ج حتى يعرف المحول البرمجي حجم فو)

التنفيذ هو:

//cfoo.cpp
#include "foo.hpp"
#include "foo.h"
Foo FooInit()
{
  cxxFoo * ret = new cxxFoo(1);
  return (void*)ret;
}
void FooFree(Foo f)
{
  cxxFoo * foo = (cxxFoo*)f;
  delete foo;
}
void FooBar(Foo f)
{
  cxxFoo * foo = (cxxFoo*)f;
  foo->Bar();
}

مع كل ذلك تم ذلك، فإن ملف Go هو:

// foo.go
package foo
// #include "foo.h"
import "C"
import "unsafe"
type GoFoo struct {
     foo C.Foo;
}
func New()(GoFoo){
     var ret GoFoo;
     ret.foo = C.FooInit();
     return ret;
}
func (f GoFoo)Free(){
     C.FooFree(unsafe.Pointer(f.foo));
}
func (f GoFoo)Bar(){
     C.FooBar(unsafe.Pointer(f.foo));
}

Makefile اعتدت على ترجمة هذا:

// makefile
TARG=foo
CGOFILES=foo.go
include $(GOROOT)/src/Make.$(GOARCH)
include $(GOROOT)/src/Make.pkg
foo.o:foo.cpp
    g++ $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $<
cfoo.o:cfoo.cpp
    g++ $(_CGO_CFLAGS_$(GOARCH)) -fPIC -O2 -o $@ -c $(CGO_CFLAGS) $<
CGO_LDFLAGS+=-lstdc++
$(elem)_foo.so: foo.cgo4.o foo.o cfoo.o
    gcc $(_CGO_CFLAGS_$(GOARCH)) $(_CGO_LDFLAGS_$(GOOS)) -o $@ $^ $(CGO_LDFLAGS)

حاول اختبارها مع:

// foo_test.go
package foo
import "testing"
func TestFoo(t *testing.T){
    foo := New();
    foo.Bar();
    foo.Free();
}

ستحتاج إلى تثبيت المكتبة المشتركة مع تثبيت التثبيت، ثم قم بتشغيل الاختبار. الإخراج المتوقع هو:

gotest
rm -f _test/foo.a _gotest_.6
6g -o _gotest_.6 foo.cgo1.go foo.cgo2.go foo_test.go
rm -f _test/foo.a
gopack grc _test/foo.a _gotest_.6  foo.cgo3.6
1
PASS

نصائح أخرى

يبدو أن SWIJ حاليا هو أفضل حل لهذا:

http://www.swig.org/doc2.0/go.html.

يدعم الميراث وحتى يسمح لفئة فئة C ++ Subclass مع GO CORTION بحيث يتم استدعاء طرق تجاوزها في رمز C ++، يتم إطلاق النار على الرمز.

قسم حول C ++ في الذهاب التعليمات يتم تحديثه والآن يذكر Swig ولم يعد يقول "لأن الذهاب هو جمع القمامة، سيكون من الحكمة القيام بذلك، على الأقل ساذجة".

لا يمكنك حتى الآن من ما قرأته في الأسئلة الشائعة:

هل تذهب برامج برامج مع برامج C / C ++؟

هناك تطبيقان Go Compiler، GC (برنامج الأصدقاء والأصدقاء 6G) و GCCGO. يستخدم GC اتفاقية استدعاء مختلفة وربدا، وبالتالي لا يمكن ربطها إلا ببرامج C باستخدام نفس الاتفاقية. هناك مثل هذا المترجم C ولكن لا يوجد مترجم C ++. GCCGO هي الواجهة الأمامية لدول مجلس التعاون الخليجي يمكن ربطها، بعناية، برامج C ++ التي تم تجميعها في دول مجلس التعاون الخليجي.

يوفر برنامج CGO آلية "واجهة الوظائف الأجنبية" للسماح بالمكالمات الآمنة للمكتبات C من كود الذهاب. يمتد Swig هذه القدرة إلى مكتبات C ++.

اعتبارا من Go1.2 +، يتضمن CGO تلقائيا وكوجه رمز C ++:

http://golang.org/doc/go1.2#cgo_and_cpp.

يبدو أنه واحد من الأسئلة المبكرة حول Golang. وفي نفس الوقت الإجابات على التحديث أبدا. خلال هذه السنوات الثلاث إلى الأربع سنوات، كانت العديد من المكتبات الجديدة ومدونات المدونة. فيما يلي الروابط القليلة التي شعرت بها مفيدة.

Swig والذهاب

استدعاء رمز C ++ من الذهاب مع Swig

حول مقارنة اللغات، C ++ والذهاب

goforcppprogrammers.

لقد قمت بإنشاء المثال التالي على أساس إجابة سكوت ويلز. وبعد لقد اختبرتها في Macos High Sierra 10.13.3 go الإصدار go1.10 darwin/amd64.

(1) رمز ل library.hpp, ، API C ++ نحن نهدف إلى الاتصال.

#pragma once
class Foo {
 public:
  Foo(int value);
  ~Foo();
  int value() const;    
 private:
  int m_value;
};

(2) رمز ل library.cpp, ، تنفيذ C ++.

#include "library.hpp"
#include <iostream>

Foo::Foo(int value) : m_value(value) {
  std::cout << "[c++] Foo::Foo(" << m_value << ")" << std::endl;
}

Foo::~Foo() { std::cout << "[c++] Foo::~Foo(" << m_value << ")" << std::endl; }

int Foo::value() const {
  std::cout << "[c++] Foo::value() is " << m_value << std::endl;
  return m_value;
}

(3) رمز ل library-bridge.h الجسر اللازم لفضح C واجهة برمجة تطبيقات تنفيذها في C++ لهذا السبب go يمكن استخدامه.

#pragma once
#ifdef __cplusplus
extern "C" {
#endif

void* LIB_NewFoo(int value);
void LIB_DestroyFoo(void* foo);
int LIB_FooValue(void* foo);

#ifdef __cplusplus
}  // extern "C"
#endif

(4) رمز ل library-bridge.cpp, ، تنفيذ الجسر.

#include <iostream>

#include "library-bridge.h"
#include "library.hpp"

void* LIB_NewFoo(int value) {
  std::cout << "[c++ bridge] LIB_NewFoo(" << value << ")" << std::endl;
  auto foo = new Foo(value);
  std::cout << "[c++ bridge] LIB_NewFoo(" << value << ") will return pointer "
            << foo << std::endl;
  return foo;
}

// Utility function local to the bridge's implementation
Foo* AsFoo(void* foo) { return reinterpret_cast<Foo*>(foo); }

void LIB_DestroyFoo(void* foo) {
  std::cout << "[c++ bridge] LIB_DestroyFoo(" << foo << ")" << std::endl;
  AsFoo(foo)->~Foo();
}

int LIB_FooValue(void* foo) {
  std::cout << "[c++ bridge] LIB_FooValue(" << foo << ")" << std::endl;
  return AsFoo(foo)->value();
}

(5) أخيرا، library.go, ، برنامج GO يدعو API C ++.

package main

// #cgo LDFLAGS: -L. -llibrary
// #include "library-bridge.h"
import "C"
import "unsafe"
import "fmt"

type Foo struct {
    ptr unsafe.Pointer
}

func NewFoo(value int) Foo {
    var foo Foo
    foo.ptr = C.LIB_NewFoo(C.int(value))
    return foo
}

func (foo Foo) Free() {
    C.LIB_DestroyFoo(foo.ptr)
}

func (foo Foo) value() int {
    return int(C.LIB_FooValue(foo.ptr))
}

func main() {
    foo := NewFoo(42)
    defer foo.Free() // The Go analog to C++'s RAII
    fmt.Println("[go]", foo.value())
}

باستخدام makefile التالية

liblibrary.so: library.cpp library-bridge.cpp
    clang++ -o liblibrary.so library.cpp library-bridge.cpp \
    -std=c++17 -O3 -Wall -Wextra -fPIC -shared

يمكنني تشغيل برنامج المثال على النحو التالي:

$ make
clang++ -o liblibrary.so library.cpp library-bridge.cpp \
    -std=c++17 -O3 -Wall -Wextra -fPIC -shared
$ go run library.go
[c++ bridge] LIB_NewFoo(42)
[c++] Foo::Foo(42)
[c++ bridge] LIB_NewFoo(42) will return pointer 0x42002e0
[c++ bridge] LIB_FooValue(0x42002e0)
[c++] Foo::value() is 42
[go] 42
[c++ bridge] LIB_DestroyFoo(0x42002e0)
[c++] Foo::~Foo(42)

الأهمية

التعليقات المذكورة أعلاه import "C" في ال go البرنامج غير اختياري. وبعد يجب أن تضعها بالضبط كما هو موضح بحيث cgo يعرف أي رأس ومكتبة لتحميل، في هذه الحالة:

// #cgo LDFLAGS: -L. -llibrary
// #include "library-bridge.h"
import "C"

رابط إلى جيثب ريبو مع المثال الكامل.

هناك حديث قابلية التشغيل البيني بين ج والذهاب عند استخدام GCC GO Compiler، GCCGO. هناك قيود على القدرة على التشغيل البيني ومجموعة الميزات المنفذة من الذهاب عند استخدام GCCGO (على سبيل المثال، محدودية Goroutines، لا مجموعة من القمامة).

أنت تمشي على أرض غير مجهولة هنا. هنا هو سبيل المثال للحصول على رمز C، ربما يمكنك القيام بشيء من هذا القبيل بعد القراءة C ++ اسم المشاهير واستدعاء الاتفاقيات، والكثير من المحاكمة والخطأ.

إذا كنت لا تزال تشعر وكأنها تحاول ذلك، حظا سعيدا.

المشكلة هنا هي أن التنفيذ المتوافق لا يحتاج إلى وضع فصولك في ملف ترجمة .cpp. إذا كان بإمكان المحول البرمجي تحسين وجود فئة، طالما أن البرنامج يتصرف بنفس الطريقة دون ذلك، فيمكن حذفها من القابل للتنفيذ من الناتج.

ج لديه واجهة ثنائية موحدة. لذلك ستتمكن من معرفة أن وظائفك يتم تصديرها. لكن C ++ ليس له مثل هذا المعيار وراء ذلك.

مضحك عدد القضايا الأوسع التي تم الرجوع إليها هذا الإعلان. كان لدى دان ليكي مناقشة مسلية للغاية ومدروسة على موقعه على الويب، Flutterby، حول النامية معايير الانبشر كوسيلة لإصلاح اللغات الجديدة (وغيرها من التداعيات، ولكن هذا هو الألم الألماني هنا).

قد تحتاج إلى إضافة -lc++ إلى LDFlags ل Golang / CGO للتعرف على الحاجة إلى المكتبة القياسية.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top