Wrapping a C struct using a Go type alias

1,071 views
Skip to first unread message

mikeb

unread,
Jun 13, 2011, 11:13:49 PM6/13/11
to golan...@googlegroups.com
I'm writing Go language bindings for a library using cgo and have some questions about wrapping structs.  My questions are about the general function of Go so I put together the example below to help illustrate.  I haven't been able to find a lot of documentation on cgo so I apologize for the numerous questions.

1. Will the expression (*C.cobject)(obj) allocate memory for a C.cobject pointer or just change the runtime type of obj?
2. Will the runtime recognize the type wrapper.Object as a C type and not move it in memory and/or deallocate it?
3. Is it safe to deallocate an object's memory inside one of the object's methods? 
4. Why isn't there a panic when referencing obj after calling Free(), it returns an empty string?
5. Is this an efficient idiom or should I prefer using Go peer objects or something else?  By peer I mean defining a Go struct for every C struct, declaring a member of the C type and the member to avoid type conversions.


package wrapper

/*
#include "stdlib.h"
#include "string.h"

typedef struct {
char *greeting;
} cobject;

cobject* create_object() {
cobject *obj = malloc(sizeof(cobject));
obj->greeting = malloc(sizeof(char) * 6);
strncpy(obj->greeting, "Hello\0", 6);
return obj;
}

void free_object(cobject *ptr) {
free(ptr);
}
*/
import "C"

import (
"os"
)

type Object C.cobject

func NewObject() *Object {
return (*Object)(C.create_object())
}

func (obj *Object) Greeting() string {
return C.GoString((*C.cobject)(obj).greeting)
}

func (obj *Object) Free() {
C.free_object((*C.cobject)(obj))
}

func Run() {
x := NewObject()
os.Stdout.WriteString(x.Greeting())
x.Free()
os.Stdout.WriteString(x.Greeting())
os.Stdout.WriteString("Bye\n")
}

Ian Lance Taylor

unread,
Jun 14, 2011, 1:49:19 AM6/14/11
to golan...@googlegroups.com
mikeb <mi...@bergin.me> writes:

> I'm writing Go language bindings for a library using cgo and have some
> questions about wrapping structs. My questions are about the general
> function of Go so I put together the example below to help illustrate. I
> haven't been able to find a lot of documentation on cgo so I apologize for
> the numerous questions.
>

> 1. Will the expression *(*C.cobject)(obj)* allocate memory for a *C.cobject*pointer or just change the runtime type of
> *obj*?

It will just change the runtime type. It's like a cast in C.

> 2. Will the runtime recognize the type *wrapper.Object* as a C type and not

> move it in memory and/or deallocate it?

The runtime won't worry about pointers that point into spaces which the
runtime did not allocate, such as anything allocated using C's malloc.
Similarly, the runtime will not see anything allocated using C's malloc,
so any pointers from there to Go structures will not be seen and the Go
structures may be collected leaving the C pointers dangling. The
runtime won't move anything allocated using C's malloc.

> 3. Is it safe to deallocate an object's memory inside one of the object's
> methods?

Yes, you can deallocate the C object as long as you are careful to not
refer to the receiver after deallocating.

> 4. Why isn't there a panic when referencing *obj* after calling *Free()*, it
> returns an empty string?

When you use free, you become responsible for avoid dangling pointers
yourself. Free is an escape hatch from the protection mechanisms built
into Go.

> 5. Is this an efficient idiom or should I prefer using Go peer objects or
> something else? By peer I mean defining a Go struct for every C struct,
> declaring a member of the C type and the member to avoid type conversions.

What you are doing is efficient but it's easy to make a mistake. I
think that if I wanted methods on a C object using cgo I would use a Go
peer object as you describe.

Ian

mikeb

unread,
Jun 14, 2011, 9:00:25 AM6/14/11
to golan...@googlegroups.com
Thank you very much for answering all of my questions, clears things up perfectly.
Reply all
Reply to author
Forward
0 new messages