C Vs Go (Golang Intro) PDF
C Vs Go (Golang Intro) PDF
C Vs Go (Golang Intro) PDF
Marcin Pasinski
Mender.io
My view on C vs Go
● What is Go
● Why did we choose go
● Go basics
● Code samples
● Demo
Who am I?
● Marcin Pasinski
● “Go was born out of frustration with existing languages and environments for
systems programming.”
● “One had to choose either efficient compilation, efficient execution, or ease of
programming; all three were not available in the same mainstream language.”
https://golang.org/doc/faq
Language requirements
1. “External impact”
○ Size requirements on device
○ Setup requirement in Yocto Project
○ Possibility to compile for multiple platforms
2. “Internal considerations”
○ Competences in the company
○ Code share/reuse
○ Development speed
○ Access to common libraries (JSON, SSL, HTTP)
○ “Automatic memory management”
○ “Security enablers” (buffer overflow protection, etc.)
Language comparison
C C++ Go
Size requirements in devices Lowest Low (1.8MB more) Low (2.1 MB more, however will increase
with more binaries)
Competence in the company Good Have some long time users Only couple of people know it
Code reuse/sharing from CFEngine Good Easy (full backwards compatibility) Can import C API
1. Golang has lots of core language features and libraries that allows much faster
development of applications.
2. The learning curve from C to Golang is very low, given the similarities in the language
structure.
3. As it is a compiled language, Golang runs natively on embedded devices.
4. Go is statically linked into a single binary, with no dependencies or libraries required at
the device (note that this is true for applications compiled with CGO_ENABLED=0).
5. Go provides wide platform coverage for cross-compilation to support different
architectures
6. Similar in size with static C binaries, Go binaries continue to get smaller as their compilers
get optimized.
7. Both the client and the backend are written in the same language
Go vs C: size
package main #include <stdio.h>
func main() {
int main(void)
println("hello world") {
} printf("hello world\n");
return 0;
● $ go build }
○ 938K
● $ go build -ldflags ‘-s -w’ ● gcc main.c
○ 682K ○ 8,5K
● $ go build & strip ● ldd a.out
○ 623K ○ linux-vdso.so.1
○ libc.so.6
package main ○ /lib64/ld-linux-x86-64.so.2
import “fmt” ● gcc -static main.c
○ 892K
func main() {
● gcc -static main.c & strip
fmt.Println("hello world")
○ 821K
}
● $ go build
○ 1,5M
Go vs C: speed
1. Go is fully garbage-collected
2. Go declaration syntax says nothing about stack and heap allocations making
those implementation dependant ($ go build -gcflags -m; )
3. Fast compilation
4. Go provides support for concurrent execution and communication
5. The speed of developer is most important in most cases and Go really excels
here
https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=go&lang2=gcc
Go basic features
● Standard library
● Tooling
● Compilation
● Concurrency
● Linking with C and C++
● Code samples
Standard library
○ fmt
○ test
○ cover
○ pprof
○ doc
○ get
○ vet
○ race detector
○ and many more
Compilation
● Compilers
○ The original gc, the Go compiler, was written in C
○ As of Go 1.5 the compiler is written in Go with a recursive descent parser
and uses a custom loader, based on the Plan 9 loader
○ gccgo (frontend for GCC; https://golang.org/doc/install/gccgo)
■ gcc 7 supports Go 1.8.1
● Compilation
○ fast (large modules compiled within seconds)
○ single binary file (no dependencies, no virtual machines)
■ from Go 1.5 possible to create shared libraries and dynamic linking but
only on x86 architecture
○ makefile
(https://github.com/mendersoftware/mender/blob/master/Makefile)
Cross compilation (https://golang.org/doc/install/source#environment)
$GOOS / $GOARCH amd64 386 arm arm64 ppc64le ppc64 mips64le mips64 mipsle mips
android X
darwin X X X
dragonfly X
freebsd X X X
linux X X X X X X X X X X
netbsd X X X
openbsd X X X
plan9 X X
solaris X
windows X X
Debugging
● Gdb
● Delve (https://github.com/derekparker/delve)
Testing
● Unit tests
● Benchmarks
● All you need:
○ add “_test” to filename
○ add “Test” to function
○ import “testing”
Variables
package main
● Functions
func div(x, y int) (int, error) {
○ take zero or more arguments
if y == 0 {
○ arguments pass by value
return 0, errors.New("div by 0")
○ multiple return values
}
return x / y, nil
}
func main() {
fmt.Println(div(4, 0))
}
Structures and methods
type Point struct {
X int
● Structs Y int
○ Struct is collection of fields }
● Methods
○ Functions with receiver type Square struct {
argument Vertex Point
objects }
○ Implemented implicitly }
■ no explicit declaration
type myType int
■ no “implements”
func (mt myType) Print() (string, error) {
● Decoupled definition and
return “this is my int”, nil
implementation
}
● Empty interface interface{}
main() {
var p Printer = myType(1)
i.Print()
}
Concurrency
● Goroutines
■ Functions that run concurrently with other
functions
■ Only few kB initial stack size (2kB)
■ Multiplexed onto OS threads as required
● Channels
■ Used for sending messages and
synchronization
■ Sends and receives block by default
■ Can be unbuffered or buffered
Concurrency cont’d
package main
● Goroutines
func main() {
○ go func()
messages := make(chan string)
go func() { messages <- "ping" }()
● Channels
○ c := make(chan int) select {
case msg := <- messages:
fmt.Println(msg)
case <- time.After(time.Second):
fmt.Println("timeout")
default:
fmt.Println("no activity")
time.Sleep(50 * time.Millisecond)
}
}
C code inside Go
/*
#cgo LDFLAGS: -lpcap
● CGO (https://golang.org/cmd/cgo/)
#include <stdlib.h>
○ allows Go to access C library #include <pcap.h>
functions and global variables */
○ imported C functions are import "C"
available under virtual C
package func getDevice() (string, error) {
○ CGO_ENABLED var errMsg string
○ There is a cost associated with cerr := C.CString(errMsg)
calling C APIs (~150ns on Xeon defer C.free(unsafe.Pointer(cerr))
processor)
cdev := C.pcap_lookupdev(cerr)
dev := C.GoString(cdev)
return dev, nil
}
C++ code inside go
// helloclass.cpp
std::string HelloClass::hello(){
● SWIG return "world";
○ Simplified Wrapper and }
Interface Generator
○ Used to create wrapper code // helloclass.h
// mylib.swig
%module mylib
%{
#include "helloclass.h"
%}
Shared Go libraries
○ -buildmode argument
■ archive import "C"
import "fmt"
■ c-archive
■ c-shared
//export SayHiElc
■ shared
func SayHiElc(name string) {
■ exe fmt.Printf("Hello ELC: %s!\n", name)
● ~ go build -buildmode=shared -o }
myshared
● ~ go build -linkshared -o app func main() {
myshared // We need the main for Go to
// compile C shared library
}
Shared C libraries
// mygolib.h
● ~ go build -buildmode=c-shared -o typedef signed char GoInt8;
typedef struct { char *p; GoInt n; }
mygolib.a mygolib.go GoString;
int main() {
printf("Go from C app.\n");
GoString name = {"Prague", 6};
SayHiElc(name);
return 0;
}
Embedded Go
● Yocto
● Mender.io
● ThermoStat ™
○ https://github.com/mendersoftware/thermostat
Q&A