CGO, how to pass NULL parameter to C function

huangapple go评论83阅读模式
英文:

CGO, how to pass NULL parameter to C function

问题

有时候,在C API中可能需要使用NULL指针。

在CGO中是否可能实现这一点?

例如,我想在Go语言程序中将一个空参数传递给strcmp()函数:

package strutil

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

func StrCmp(a, b string) int {
    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)
}

如果我将pca设置为nil,会出现以下错误:

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, ...)

那么,我该如何将NULL传递给strcmp函数呢?

谢谢。

英文:

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 &lt;stdlib.h&gt;
#include &lt;string.h&gt;
*/
import (
    &quot;C&quot;
    &quot;unsafe&quot;
)

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

答案1

得分: 14

如果你想将NULL传递给C函数,你可以简单地将nil传递给它。

然而,当你将一个NULL指针传递给函数strcmp(...)时,文档中没有说明会发生什么。我猜想,当你将NULL传递给它时,strcmp会失败。最好在之前检查输入,并在其中一个输入设置为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))
}

如果有必要,下面是一个接受NULL指针的函数如何传递NULL的示例:

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))))
}
英文:

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 &lt;stdlib.h&gt;
#include &lt;string.h&gt;
*/
import &quot;C&quot;

import (
	&quot;errors&quot;
	&quot;fmt&quot;
	&quot;unsafe&quot;
)

func StrCmp(a, b *string) (int, error) {
	if nil == a || nil == b {
		return 0, errors.New(&quot;Both strings have to be set&quot;)
	}
	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 := &quot;Left&quot;
	right := &quot;Right&quot;
	fmt.Println(StrCmp(&amp;left, &amp;right))
	fmt.Println(StrCmp(&amp;left, &amp;left))
	fmt.Println(StrCmp(nil, &amp;right))
	fmt.Println(StrCmp(&amp;left, nil))
}

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

package main

/*
#include &lt;stdio.h&gt;
int am_i_null(int* pointer) {
  if (NULL == pointer) {
    return -1;
  }
  return *pointer;
}
*/
import &quot;C&quot;

import (
	&quot;fmt&quot;
	&quot;unsafe&quot;
)

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

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

	var goInteger int = 7
	fmt.Println(C.am_i_null((*C.int)(unsafe.Pointer(&amp;goInteger))))
}

huangapple
  • 本文由 发表于 2015年3月6日 21:42:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/28900065.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定