Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CGO, how to pass NULL parameter to C function

Sometimes, a NULL pointer may be needed for a C API.

is that possible in CGO?

For example, I want to pass a null argument to strcmp() in a Go language program:

package strutil

/*
#include <stdlib.h>
#include <string.h>
*/
import (
    "C"
    "unsafe"
)

func StrCmp(a, b string) int {
    pca := C.CString(a)
    defer C.free(pca)
    pcb := C.CString(b)
    defer C.free(pcb)
    ret := C.strcmp(pca, pcb)
    return int(ret)
}

If I set pca to nil, this error occurs:

Exception 0xc0000005 0x0 0x0 0x76828b21
PC=0x76828b21
signal arrived during cgo execution

strutil._Cfunc_strcmp(0x0, 0x761b00, 0x0)
    strutil/_obj/_cgo_gotypes.go:79 +0x49
strutil.StrCmp(0x19, 0x10, 0x4bbf38, 0xa, 0x1fbc1f98, 0x0, 0x0, 0xffff, 0x0,     0x0, ...)

So, how can I pass NULL to strcmp?

Thanks

like image 425
tanbro Avatar asked Mar 06 '15 13:03

tanbro


1 Answers

If you want to pass NULL to a C function you could simply pass nil into it.

However it's not documented what happens when you send a NULL pointer to the function strcmp(...). I'd guess that the strcmp fails when you are passing NULL to it. It would be better to check your input on before hand and return an error when one of your inputs is set to nil.

package main

/*
#include <stdlib.h>
#include <string.h>
*/
import "C"

import (
    "errors"
    "fmt"
    "unsafe"
)

func StrCmp(a, b *string) (int, error) {
    if nil == a || nil == b {
        return 0, errors.New("Both strings have to be set")
    }
    pca := C.CString(*a)
    defer C.free(unsafe.Pointer(pca))
    pcb := C.CString(*b)
    defer C.free(unsafe.Pointer(pcb))

    ret := C.strcmp(pca, pcb)
    return int(ret), nil
}

func main() {
    left := "Left"
    right := "Right"
    fmt.Println(StrCmp(&left, &right))
    fmt.Println(StrCmp(&left, &left))
    fmt.Println(StrCmp(nil, &right))
    fmt.Println(StrCmp(&left, nil))
}

If necessary an example how to pass NULL to a function that does accept NULL pointers:

package main

/*
#include <stdio.h>
int am_i_null(int* pointer) {
  if (NULL == pointer) {
    return -1;
  }
  return *pointer;
}
*/
import "C"

import (
    "fmt"
    "unsafe"
)

func main() {
    fmt.Println(C.am_i_null(nil))

    var cInteger C.int = 8
    fmt.Println(C.am_i_null(&cInteger))

    var goInteger int = 7
    fmt.Println(C.am_i_null((*C.int)(unsafe.Pointer(&goInteger))))
}
like image 102
Sander Avatar answered Sep 19 '22 04:09

Sander