Last Updated: February 25, 2016
· ysgard

Pass Go slices as C array parameters

I've found (while working with the excellent OpenGL wrapper, GoGL) that I often need to pass a 'naked' C array to the underlying OpenGL API. For example, the function glBufferData requires a pointer to a C float array.

I prefer working with slices, so it wasn't immediately clear to me how I could pass them to OpenGL as needed. Some Googling and experimentation yielded the answer: Anytime you have a Go []int, and want to pass it to a C *int, you can do:

intSlice := []int{0, 1, 2, 3, 4}
some_func_requiring_intptr( &intSlice[0] )

Doing an &intSlice won't do, as that gives the address of the slice, not the array within. Probably obvious to the pros, but here's hoping it will save someone new to Go some time.

4 Responses
Add your response

yes, the reason is here:

struct Slice
    {   // must not move anything
        byte*   array;      // actual data
        uint32  len;        // number of elements
        uint32  cap;        // allocated number of elements
over 1 year ago ·

@becreative-germany Interesting - so why doesn't &intSlice work then? It should pass the address to the struct, and since the array is the first data member defined in the struct, wouldn't that effectively be a pointer to the array?

over 1 year ago ·

@ysgard strange that I don´t get any notifiaction about comments sry. A Slice is always just a reference to an array with a length and a capacity so the overhead is very small. In this case &intSlice referenced to the Slice not to the underlying Array. By the reason that a Slice ist just a reference to the Array the first element of a Slice &intSlice[0] is the first Element of the underlying Array (without reslicing) and so the start address of the Array.

var c int = 1

intSlice := []int{100, 1, 2, 3, 4}
newSlice := intSlice[c:]

fmt.Printf("Points to the Slice %p\n",&intSlice) //0xc20005d020
fmt.Printf("Points to the first Element of the underlying Array: %d\n",&intSlice[0]) //833223995872

fmt.Printf("Points to the newSlice first Element and not to the Array: %d\n",&newSlice[0]) //833223995880
fmt.Printf("%v",newSlice[0]) //0

ref := reflect.ValueOf(newSlice)
t := reflect.TypeOf(newSlice)

//Start address of the underlying Array. But that´s critical in my opinion.
addr := int(ref.Pointer()) - (t.Align() * c) //833223995872

fmt.Printf("Addr of the underlying data: %d\n",addr) //833223995872

underArray := (*[5]int)(unsafe.Pointer(uintptr(addr)))
fmt.Println( *underArray ) //[100 1 2 3 4]
over 1 year ago ·

How would you do it for a slice of strings?

over 1 year ago ·