Cgo и Go изцяло на Go

15.12.2015

Но преди това

Въпроси за мъфини

Въпрос #1

Как се подават флагове за регулярни изрази в Go?

Въпрос #2

Какво е error?

Въпрос #3

Къде пишем документацията на нашите фунцкии, структури и пакети?

Въпрос #4

Как се въстановяваме от паника?

defer func() {
    if r := recover(); r != nil {
        // There was a panic
    }
}()

Днес ще видите

C? Go? Cgo!

C в .go файлове

package main

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

func Random() int {
    return int(C.random())
}

func Seed(i int) {
    C.srandom(C.uint(i))
}

Особености

// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"
// #cgo pkg-config: png cairo

Go в .c файлове (1)

package goc

import "C"

//export GreetFromGo
func GreetFromGo(name string) {
    println("Hello from Go, ", name)
}

func main() {
    // Needed by cgo in order to generate a library
}

Go в .c файлове (2)

go build -buildmode=c-archive -o goc.a goc.go
extern void GreetFromGo(GoString p0);

Go в .c файлове (3)

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

int main() {
  printf("Hi, I am a C program.\n");
  GoString name = {"Doycho", 4};
  GreetFromGo(name);
  return 0;
}
gcc -o out goc.c goc.a

Никога не е толкова просто

Стигне ли се до компилиране на C, забравете за лесно:

Но, за това пък, има много от:

Още от магиите на "C"

Error handling

n, err := C.sqrt(-1)

Function pointers

Мoля?

package main

// typedef int (*intFunc) ();
//
// int
// bridge_int_func(intFunc f)
// {
//      return f();
// }
//
// int fortytwo()
// {
//      return 42;
// }
import "C"
import "fmt"

func main() {
    f := C.intFunc(C.fortytwo)
    fmt.Println(int(C.bridge_int_func(f)))
    // Output: 42
}

Друг начин за викане на Go от C

package main

func Add(a, b int) int {
    return a + b
}

Друг начин за викане на Go от C (2)

#include <stdio.h>

extern int go_add(int, int) __asm__ ("example.main.Add");

int main() {
  int x = go_add(2, 3);
  printf("Result: %d\n", x);
}

Друг начин за викане на Go от C (3)

all: main

main: foo.o bar.c
    gcc foo.o bar.c -o main

foo.o: foo.go
    gccgo -c foo.go -o foo.o -fgo-prefix=example

clean:
    rm -f main *.o

Указатели без граници

package unsafe

Декларира невинно изглеждащите:

реално тези дефиниции съществуват главно за документация, имплементацията е в компилатора.

Safety third

unsafe.Pointer има четири важни харектеристики

Това е практическо заобикаляне на типовата система в Go.

Unsafe пример:

package main

/*
#include <stdlib.h>
*/
import "C"
import (
    "fmt"
    "unsafe"
)

func main() {
    cs := C.CString("42")            // alloc on C's heap
    defer C.free(unsafe.Pointer(cs)) // don't leak
    answer := C.atoi(cs)
    fmt.Println(answer)
}

Адресна аритметика:

package main

import "unsafe"
import "fmt"

type slice struct {
    array      unsafe.Pointer
    size, _cap int
}

func main() {
    var p = []string{"Hello", " "}
    p = append(p, "World!")
    var s = (*slice)(unsafe.Pointer(&p))
    var sizeOfString = unsafe.Sizeof("")
    fmt.Printf("size=%d, cap=%d\n", s.size, s._cap)
    for i := 0; s.size > i; i++ {
        fmt.Printf("[%d]: `%s`\n", i,
            *(*string)(unsafe.Pointer(uintptr(s.array) + uintptr(i)*sizeOfString)))
    }
}

Go in Go

С? Защо?

Компилатор

Runtime

Как се махат хиляди редове С?

Производителност

Също преминали в Go Land:

GODEBUG

Добре, компилира се!

Повече информация

export GODEBUG="name=flag"

Пример:

export GODEBUG="gctrace=2,invalidptr=1"

Позволява:

...

GOGC

Въпроси?