Экспорт Go-функций в C

Экспорт Go-функций в C с помощью cgo позволяет вызывать код, написанный на Go, из программ на C. Для этого используется директива //export, которая делает Go-функцию доступной для C-кода. В качестве параметров функция может принимать стандартные типы C (C.int, C.char* и другие), а возвращать - соответствующие значения.

Синтаксис

go//export FunctionName
func FunctionName(param1 C.int, param2 *C.char) C.int {
  // тело функции
}

Пример

Давайте создадим простую Go-функцию, которая принимает два целых числа и возвращает их сумму:

gopackage main

/*
#include <stdio.h>
*/
import "C"
import "fmt"

//export Sum
func Sum(a C.int, b C.int) C.int {
  res := a + b
  fmt.Printf("Sum of %d and %d is %d\n", a, b, res)
  return res
}

func main() {
  // функция main необходима для компиляции,
  // но она не используется при экспорте
}

Теперь эту функцию можно вызвать из C-программы:

go#include <stdio.h>

extern int Sum(int a, int b);

int main() {
  int result = Sum(5, 7);
  printf("Result from Go: %d\n", result);
  return 0;
}

Результат выполнения C-программы:

go"Sum of 5 and 7 is 12"
"Result from Go: 12"

Пример

Рассмотрим более сложный пример, где Go-функция принимает C-строку и возвращает новую C-строку:

gopackage main

/*
#include <stdlib.h>
*/
import "C"
import "strings"
import "unsafe"

//export ToUpper
func ToUpper(str *C.char) *C.char {
  goStr := C.GoString(str)
  upperStr := strings.ToUpper(goStr)
  return C.CString(upperStr)
}

//export FreeString
func FreeString(str *C.char) {
  C.free(unsafe.Pointer(str))
}

func main() {}

C-программа, использующая эту функцию:

go#include <stdio.h>
#include <stdlib.h>

extern char* ToUpper(char* str);
extern void FreeString(char* str);

int main() {
  char* input = "hello world";
  char* result = ToUpper(input);
  printf("Original: %s\n", input);
  printf("Upper: %s\n", result);
  FreeString(result);
  return 0;
}

Результат выполнения C-программы:

go"Original: hello world"
"Upper: HELLO WORLD"

Пример

Экспортированная функция может возвращать структуры. Рассмотрим пример с экспортом функции, возвращающей структуру C:

gopackage main

/*
typedef struct {
  int x;
  int y;
} Point;
*/
import "C"

//export CreatePoint
func CreatePoint(x C.int, y C.int) C.Point {
  return C.Point{x: x, y: y}
}

//export SumPoint
func SumPoint(p C.Point) C.int {
  return p.x + p.y
}

func main() {}

C-программа, использующая эти функции:

go#include <stdio.h>

typedef struct {
  int x;
  int y;
} Point;

extern Point CreatePoint(int x, int y);
extern int SumPoint(Point p);

int main() {
  Point p = CreatePoint(10, 20);
  int sum = SumPoint(p);
  printf("Point: (%d, %d)\n", p.x, p.y);
  printf("Sum: %d\n", sum);
  return 0;
}

Результат выполнения C-программы:

go"Point: (10, 20)"
"Sum: 30"

Смотрите также

  • директиву //export,
    которая делает Go-функцию доступной для C
  • функцию C.CString,
    которая преобразует Go-строку в C-строку
  • функцию C.GoString,
    которая преобразует C-строку в Go-строку
  • функцию C.free,
    которая освобождает память, выделенную в C