Buscar..
Llamando a la función C desde Go
Cgo permite la creación de paquetes Go que llaman código C
Para usar cgo
escriba el código Go normal que importa un pseudo-paquete "C". El código Go puede hacer referencia a tipos como C.int
o funciones como C.Add
.
La importación de "C" está precedida inmediatamente por un comentario, ese comentario, denominado preámbulo, se usa como encabezado al compilar las partes C del paquete.
Tenga en cuenta que no debe haber líneas en blanco entre el comentario de cgo
y la declaración de importación.
Tenga en cuenta que la import "C"
no se puede agrupar con otras importaciones en una declaración de importación "factorizada" entre paréntesis. Debe escribir varias declaraciones de importación, como:
import "C"
import "fmt"
Y es un buen estilo usar la declaración de importación factorizada, para otras importaciones, como:
import "C"
import (
"fmt"
"math"
)
Ejemplo simple usando cgo
:
package main
//int Add(int a, int b){
// return a+b;
//}
import "C"
import "fmt"
func main() {
a := C.int(10)
b := C.int(20)
c := C.Add(a, b)
fmt.Println(c) // 30
}
Entonces go build
, y ejecútalo, salida:
30
Para cgo
paquetes cgo
, simplemente use go build
o go install
como de costumbre. La go tool
reconoce la importación especial en "C"
y utiliza automáticamente cgo
para esos archivos.
Cable C y Go en todas las direcciones.
Llamando al código C desde Go
package main
/*
// Everything in comments above the import "C" is C code and will be compiles with the GCC.
// Make sure you have a GCC installed.
int addInC(int a, int b) {
return a + b;
}
*/
import "C"
import "fmt"
func main() {
a := 3
b := 5
c := C.addInC(C.int(a), C.int(b))
fmt.Println("Add in C:", a, "+", b, "=", int(c))
}
Llamando al código Go desde C
package main
/*
static inline int multiplyInGo(int a, int b) {
return go_multiply(a, b);
}
*/
import "C"
import (
"fmt"
)
func main() {
a := 3
b := 5
c := C.multiplyInGo(C.int(a), C.int(b))
fmt.Println("multiplyInGo:", a, "*", b, "=", int(c))
}
//export go_multiply
func go_multiply(a C.int, b C.int) C.int {
return a * b
}
Tratar con punteros de función
package main
/*
int go_multiply(int a, int b);
typedef int (*multiply_f)(int a, int b);
multiply_f multiply;
static inline init() {
multiply = go_multiply;
}
static inline int multiplyWithFp(int a, int b) {
return multiply(a, b);
}
*/
import "C"
import (
"fmt"
)
func main() {
a := 3
b := 5
C.init(); // OR:
C.multiply = C.multiply_f(go_multiply);
c := C.multiplyWithFp(C.int(a), C.int(b))
fmt.Println("multiplyInGo:", a, "+", b, "=", int(c))
}
//export go_multiply
func go_multiply(a C.int, b C.int) C.int {
return a * b
}
Convertir tipos, estructuras de acceso y aritmética de punteros
De la documentación oficial de Go:
// Go string to C string
// The C string is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CString(string) *C.char
// Go []byte slice to C array
// The C array is allocated in the C heap using malloc.
// It is the caller's responsibility to arrange for it to be
// freed, such as by calling C.free (be sure to include stdlib.h
// if C.free is needed).
func C.CBytes([]byte) unsafe.Pointer
// C string to Go string
func C.GoString(*C.char) string
// C data with explicit length to Go string
func C.GoStringN(*C.char, C.int) string
// C data with explicit length to Go []byte
func C.GoBytes(unsafe.Pointer, C.int) []byte
Cómo usarlo:
func go_handleData(data *C.uint8_t, length C.uint8_t) []byte {
return C.GoBytes(unsafe.Pointer(data), C.int(length))
}
// ...
goByteSlice := []byte {1, 2, 3}
goUnsafePointer := C.CBytes(goByteSlice)
cPointer := (*C.uint8_t)(goUnsafePointer)
// ...
func getPayload(packet *C.packet_t) []byte {
dataPtr := unsafe.Pointer(packet.data)
// Lets assume a 2 byte header before the payload.
payload := C.GoBytes(unsafe.Pointer(uintptr(dataPtr)+2), C.int(packet.dataLength-2))
return payload
}