go cgo skill
// int EC60789803D1(const char *CompanyTag, char *dataIn, int inlen, unsigned char *dataout, int outlen);
// Encrypt
{
var byteOutBuffer []byte
byteOutBuffer = make( []byte, 2048 )
var outlen int = 2048
var strKey string
strKey = "test"
var inString string
inString = "fdsafdsafdsa"
fmt.Println( "inlen=", len(inString) )
InKey := C.CString( strKey )
InData := C.CString( inString )
InInLen := C.int( len(inString) )
InOut := (*C.uchar)( &byteOutBuffer[0] )
InOutLen := C.int( outlen )
iRet := C.EC60789803D1( InKey, InData, InInLen, InOut, InOutLen )
fmt.Println( "C.EC60789803D1 ret=", iRet, " OutBuffer=", util.Bytes2str( byteOutBuffer ) )
}
cgo 可以在 go 语言中夹杂着 C 函数或数据,在使用 cgo 时,有一些需要注意的:
1、go 中的 int/int32/int64/uint32/uint64 和 C 语言中的 int/int32 等是不同的,因此,C 语言的函数的参数不能是 go 语言的 int,需要转换,同理,go 函数的 int 也不能使用 C 的 int,需要转换。
C.int(n)
还有一点,C 的函数调用中,有很多参数是 size_t 类型,其实就是一个整型,但如果使用 C.int() 作为 C 函数的参数,就会编译出错:
cannot use _Ctype_int(100) (type C.int) as type C.size_t in function argument
go 编译器严格限制参数类型必须一致,因此必须是 size_t 类型的参数。这是因为 go 语言没有 C 语言里面的强制转换的概念,你可以使用
C.size_t(n) 来得到 C 语言中的 sizt_t 类型。
2、go 语言中的字符串和 C 语言中的字符串转换
char * C.Cstring() string C.GoString()
3、结构体
使用 C.struct_xxxx 可以直接访问结构体中的成员
如果使用 struct 中的成员变量, 可以直接用. 来访问。
typedef struct face_t face_t;
struct face_t {
int x;
int y;
int w;
int h;
int neighbors;
int angle;
};
var t C.face_t
face[i].X = int(t.x)
face[i].Y = int(t.y)
face[i].W = int(t.w)
4、指针
使用 unsafe.Pointer() 来转换,例如需要转换为c中的 int *
: (*C.int)(unsafe.Pointer(&v))
在 c 语言中,指针即数组,可以使用 ptr[n] 来获得指针的第 n 个偏移,但在 go 中,这样不行,会报错:
invalid operation:xxxx
go 语言中,指针没有这样的操作。
unsafe.Pointer 对应 void * 代表的是一个指针
uintprt 表示的是一个指针的地址值
需要使用 unsafe.Pointer 和 uintptr 配合来获取指针的偏移。
5、函数调用
C.func()
文档中说,go 调用所有的 C 函数都会返回两个值,后一个值为 error 类型,即使是 void 函数。文档表述如下:
n, err := C.sqrt(-1)
_, err := C.voidFunc()
但我发现,C.malloc 似乎只返回一个值。
6、C 语言中的 NULL 在 go 中是 nil
例如
s := C.malloc(C.sizeof(100))
if s == nil {
….
}
这个很重要,在没发现 nil 可以比较 c 的指针前,我是这样比较的:
(*C.char)(unsafe.Pointer(uintptr(0)))
不过,cgo 的文档还很匮乏,很多都需要阅读代码。
package main
/*
#include
#include
#include
struct t {
char *s;
};
*/
import “C”
import “unsafe”
import “fmt”
func main() {
var t C.struct_t
var pch *C.char
var tmp *C.char
// 1. go 实现再C中分配内存
// 分配空间, 并判断是否分配成功
t.s = (*C.char)(C.malloc(C.size_t(100)))
if t.s == nil {
//if t.s == (*C.char)(unsafe.Pointer(uintptr(0))) {
panic(“malloc failed!\n”)
}
// 释放内存
defer C.free(unsafe.Pointer(t.s))
// 2. 将go的字符串转为c的字符串,并自动释放
var s = “hello world”
pch = C.CString(s)
defer C.free(unsafe.Pointer(pch))
// 调用C的strncpy函数复制
C.strncpy(t.s, pch, C.size_t(len(s)))
// C的指针操作
for i := C.size_t(0); i < C.strlen(t.s); i ++ {
tmp = (*C.char)(unsafe.Pointer(uintptr(unsafe.Pointer(t.s)) + uintptr(i)))
*tmp = C.char(C.toupper(C.int(*tmp)))
}
fmt.Printf(“%s\n”, C.GoString(t.s))
fmt.Printf(“sizeof struct t is %v\n”, unsafe.Sizeof(t))
}
package main
/*
#include <stdlib.h>
#include <string.h>
char* xmalloc(int len, int *rlen)
{
static const char* s = "0123456789";
char* p = malloc(len);
if (len <= strlen(s)) {
memcpy(p, s, len);
} else {
memset(p, 'a', len);
}
*rlen = len;
return p;
}
*/
import "C"
import "unsafe"
import "fmt"
func main() {
rlen := C.int(0)
len := 10
cstr := C.xmalloc(C.int(len), &rlen)
defer C.free(unsafe.Pointer(cstr))
gostr := C.GoStringN(cstr, rlen)
fmt.Printf("retlen=%v\n", rlen)
println(gostr)
}
go 调用C 中的struct
package main
/*
#include <stdlib.h>
#include <string.h>
struct MyString
{
char* s;
int len;
};
struct MyString xmalloc(int len)
{
static const char* s = "0123456789";
char* p = malloc(len);
if (len <= strlen(s)) {
memcpy(p, s, len);
} else {
memset(p, 'a', len);
}
struct MyString str;
str.s = p;
str.len = len;
return str;
}
*/
import "C"
import "unsafe"
import "fmt"
func main() {
len := 10
str := C.xmalloc(C.int(len))
defer C.free(unsafe.Pointer(str.s))
gostr := C.GoStringN(str.s, str.len)
fmt.Printf("retlen=%v\n", str.len)
println(gostr)
}
函数调用
package magick
/*
#cgo pkg-config: MagickCore
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <magick/MagickCore.h>
void SetImageInfoFilename(ImageInfo *image_info, char *filename)
{
(void) CopyMagickString(image_info->filename,filename,MaxTextExtent);
}
Image *AddShadowToImage(Image *image, char *colorname, const double opacity, const double sigma,const ssize_t x_offset,const ssize_t y_offset, ExceptionInfo *exception)
{
Image *shadow_image;
if (QueryColorDatabase(colorname, &image->background_color, exception) == MagickFalse) {
return MagickFalse;
}
shadow_image = ShadowImage(image, opacity, sigma, x_offset, y_offset, exception);
AppendImageToList(&shadow_image, image);
if (QueryColorDatabase("none", &shadow_image->background_color, exception) == MagickFalse) {
return MagickFalse;
}
image = MergeImageLayers(shadow_image, MergeLayer, exception);
DestroyImage(shadow_image);
return image;
}
*/
import "C"
import (
"io/ioutil"
"math"
"os"
"strings"
"unsafe"
)
func init() {
wd, err := os.Getwd()
if err != nil {
panic(err)
}
c_wd := C.CString(wd)
C.MagickCoreGenesis(c_wd, C.MagickFalse)
defer C.free(unsafe.Pointer(c_wd))
}
// Shadow adds a dropshadow to the current (transparent) image and stores the shadowed image in place
// For more information about shadow options see: http://www.imagemagick.org/Usage/blur/#shadow
func (im *MagickImage) Shadow(color string, opacity, sigma float32, xoffset, yoffset int) (err error) {
c_opacity := (C.double)(opacity)
c_sigma := (C.double)(sigma)
c_x := (C.ssize_t)(xoffset)
c_y := (C.ssize_t)(yoffset) // go类型转换为CGO size_t 类型
c_color := C.CString(color) // go类型转换为CGO sting 类型
defer C.free(unsafe.Pointer(c_color))
new_image := C.AddShadowToImage(im.Image, c_color, c_opacity, c_sigma, c_x, c_y, exception)
if failed := C.CheckException(exception); failed == C.MagickTrue {
return ErrorFromExceptionInfo(exception)
}
im.ReplaceImage(new_image)
return nil
}