這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
在嵌入式開發中總少不了和C/C++打交道,而在開發中也總有某些需求要用到某些其他工具的特性,比如go語言。
Go語言專門針對多處理器系統應用程式的編程進行了最佳化,使用Go編譯的程式可以媲美C或C++代碼的速度,而且更加安全、支援並行進程。
Go語言的文法接近C語言,但是對於變數的聲明是不同的,其他文法不同之處是For迴圈和if判斷語句不需要用小括弧括起來。Go語言支援記憶體回收功能。
與C++相比,Go語言並不包括如異常處理、繼承、泛型、斷言、虛函數等功能,但增加了slice型、並發、管道、記憶體回收、介面(interface)等特性的語言級支援。
當前有兩個Go語言的編譯器的分支。官方編譯器gc和gccgo。官方編譯器支援跨平台編譯(但不支援CGO)
go還可以嵌入C代碼,但是不可以嵌入C++代碼,當然也可以通過某些方式調用C++ API(如SWIG),本文主要講CGO。怎麼嵌入C或者調用動態庫就簡單略過了,主要注意下:
- 可以用注釋符
//和/**/包圍C代碼
- import “C” 和包含C代碼之間是沒有空行的
- 動態庫的匯入和編譯選項通過LDFLAGS、CFLAGS/CXXFLAGS來設定
- 還可以用pkg-config
#cgo pkg-config : xxxxname
- 編譯宏定義指定
#cgo CFLAGS: -DNDEBUG -DXXXX=2
今天先看看go和c之間的類型轉換:
char --> C.char --> bytesigned char --> C.schar --> int8unsigned char --> C.uchar --> uint8short int --> C.short --> int16short unsigned int --> C.ushort --> uint16int --> C.int --> intunsigned int --> C.uint --> uint32long int --> C.long --> int32 or int64long unsigned int --> C.ulong --> uint32 or uint64long long int --> C.longlong --> int64long long unsigned int --> C.ulonglong --> uint64float --> C.float --> float32double --> C.double --> float64wchar_t --> C.wchar_t --> void * -> unsafe.Pointer
編程測試:
package main/*#include <stdio.h>#include <stdlib.h>char ch = 'M';unsigned char uch = 253;short st = 233;int i = 257;long lt = 11112222;float f = 3.14;double db = 3.15;void * p;char *str = "const string";char str1[64] = "char array";void printI(void *i){ printf("print i = %d\n", (*(int *)i));}struct ImgInfo { char *imgPath; int format; unsigned int width; unsigned int height;};void printStruct(struct ImgInfo *imgInfo){ if(!imgInfo) { fprintf(stderr, "imgInfo is null\n"); return ; } fprintf(stdout, "imgPath = %s\n", imgInfo->imgPath); fprintf(stdout, "format = %d\n", imgInfo->format); fprintf(stdout, "width = %d\n", imgInfo->width);}*/import "C"import ( "fmt" "reflect" "unsafe")func main() { fmt.Println("----------------Go to C---------------") fmt.Println(C.char('Y')) fmt.Printf("%c\n", C.char('Y')) fmt.Println(C.uchar('C')) fmt.Println(C.short(254)) fmt.Println(C.long(11112222)) var goi int = 2 // unsafe.Pointer --> void * cpi := unsafe.Pointer(&goi) C.printI(cpi) fmt.Println("----------------C to Go---------------") fmt.Println(C.ch) fmt.Println(C.uch) fmt.Println(C.st) fmt.Println(C.i) fmt.Println(C.lt) f := float32(C.f) fmt.Println(reflect.TypeOf(f)) fmt.Println(C.f) db := float64(C.db) fmt.Println(reflect.TypeOf(db)) fmt.Println(C.db) // 區別常量字串和char數組,轉換成Go類型不一樣 str := C.GoString(C.str) fmt.Println(str) fmt.Println(reflect.TypeOf(C.str1)) var charray []byte for i := range C.str1 { if C.str1[i] != 0 { charray = append(charray, byte(C.str1[i])) } } fmt.Println(charray) fmt.Println(string(charray)) for i := 0; i < 10; i++ { imgInfo := C.struct_ImgInfo{imgPath: C.CString("../images/xx.jpg"), format: 0, width: 500, height: 400} defer C.free(unsafe.Pointer(imgInfo.imgPath)) C.printStruct(&imgInfo) } fmt.Println("----------------C Print----------------")}
輸出結果:
----------------Go to C---------------89Y6725411112222----------------C to Go---------------7725323325711112222float323.14float643.15const string[64]main._Ctype_char[99 104 97 114 32 97 114 114 97 121]char array----------------C Print----------------print i = 2imgPath = ../images/xx.jpgformat = 0width = 500imgPath = ../images/xx.jpgformat = 0width = 500imgPath = ../images/xx.jpgformat = 0width = 500imgPath = ../images/xx.jpgformat = 0width = 500
總結
在基本類型中,C和go之間的類型轉換還是比較方便的。但是區分字串和字元數組是不同的類型。其中有個很重要的轉換:void * -> unsafe.Pointer
https://golang.org/cmd/cgo/
https://zh.wikipedia.org/wiki/Go#cite_note-6