Вызвать функцию Go со строковым параметром из C?

Я могу вызвать функцию Go без параметров из C, см. ниже. Это компилируется через go build и печатает

Hello from Golang main function! CFunction says: Hello World from CFunction! Hello from GoFunction!

main.go

package main

//extern int CFunction();
import "C"
import "fmt"

func main() {
  fmt.Println("Hello from Golang main function!")
  //Calling a CFunction in order to have C call the GoFunction
  C.CFunction();
}

//export GoFunction
func GoFunction() {
  fmt.Println("Hello from GoFunction!")
}

файл1.c

#include <stdio.h>
#include "_cgo_export.h"

int CFunction() {
  char message[] = "Hello World from CFunction!";
  printf("CFunction says: %s\n", message);
  GoFunction();
  return 0;
}

Теперь я хочу передать массив строк/символов из C в GoFunction.

Согласно «C ссылкам на Go» в документации cgo это возможно, поэтому я добавляю строковый параметр в GoFunction и передать массив символов message в GoFunction:

main.go

package main

//extern int CFunction();
import "C"
import "fmt"

func main() {
  fmt.Println("Hello from Golang main function!")
  //Calling a CFunction in order to have C call the GoFunction
  C.CFunction();
}

//export GoFunction
func GoFunction(str string) {
  fmt.Println("Hello from GoFunction!")
}

файл1.c

#include <stdio.h>
#include "_cgo_export.h"

int CFunction() {
  char message[] = "Hello World from CFunction!";
  printf("CFunction says: %s\n", message);
  GoFunction(message);
  return 0;
}

После go build я получаю эту ошибку:

./file1.c:7:14: error: passing 'char [28]' to parameter of incompatible type 'GoString' ./main.go:50:33: note: passing argument to parameter 'p0' here

Другие ссылки: https://blog.golang.org/c-go-cgo (недостаточно репутации, чтобы опубликовать 3 ссылки) Согласно разделу «строки и прочее» приведенного выше сообщения в блоге: «Преобразование между строками Go и C выполняется с помощью C.CString, C.GoString и C. Функции GoStringN." но они предназначены для использования в Go и бесполезны, если я хочу передать строковые данные в Go.


go c cgo
person Joe Perks    schedule 26.09.2016    source источник
comment
Если вы прочитаете документацию по этому вопросу, будет создан _cgo_export.h с типом GoString, который вы можете использовать. Похоже на: typedef struct { const char *p; GoInt n; } GoString   -  person JimB    schedule 26.09.2016


Ответы (2)


Строка в C — это *C.char, а не Go string. Сделайте так, чтобы ваша экспортированная функция принимала правильный тип C и преобразовывала его по мере необходимости в Go:

//export GoFunction
func GoFunction(str *C.char) {
    fmt.Println("Hello from GoFunction!")
    fmt.Println(C.GoString(str))
}
person JimB    schedule 26.09.2016
comment
Я думаю, что ОП спрашивал, как можно вызвать функцию Go, которая принимает только строки Go. Но я думаю, что создание функции-оболочки - один из способов сделать это. - person Ainar-G; 26.09.2016
comment
@Ainar-G: хорошее замечание, мне нужно было просто дождаться ответа на комментарий ;) - person JimB; 26.09.2016
comment
Это работает! Когда я попробовал это во время устранения неполадок, я неправильно использовал str *C.Char, что привело к ошибке could not determine kind of name for C.Char - person Joe Perks; 26.09.2016
comment
@JoePrvacy Посмотрите мой ответ, если вам действительно нужно, чтобы str было string. - person Ainar-G; 26.09.2016

Если вы хотите передать строку C функции, которая принимает только строки Go, вы можете использовать тип GoString на стороне C:

char message[] = "Hello World from CFunction!";
printf("CFunction says: %s\n", message);
GoString go_str = {p: message, n: sizeof(message)}; // N.B. sizeof(message) will
                                                    // only work for arrays, not
                                                    // pointers.
GoFunction(go_str);
return 0;
person Ainar-G    schedule 26.09.2016
comment
Спасибо большое! Я проголосовал, но это не будет отображаться на счетчике, так как у меня низкая репутация. - person Joe Perks; 26.09.2016