为什么在下面的代码中,将Go字节传递给C时,字节的长度在cgo中不匹配?

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

Why passing Go bytes to C, the bytes length doesn't match in cgo in this code below?

问题

将golang字节传递给C时,字节长度不匹配。

结果的strlen(key)和keylen不匹配。

使用"go build file.go"进行构建。

您可以在下面的链接中下载go文件:
https://pastebin.com/raw/hnMfXJKq
<- 有人知道为什么我的cgo调用[]bytes到c时会出错吗?为什么strlen不匹配?

预期输出应该是相同的键长度。有时有效,有时无效。

package main
/*
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <assert.h>

void replaceK(void *key, size_t keylen, void *value, size_t valuelen);
void replaceK(void *key, size_t keylen, void *value, size_t valuelen)
{
        printf("replaceK : key = %s = %lu = %lu = %s = %lu\n",(char*) key,keylen,strlen(key),(char*) value,valuelen);
        if (keylen != strlen(key)){
                printf("ERROR!!! keylen : %lu != strlen(key) : %lu!!!\n",keylen,strlen(key));
                exit(1);
        }
}
*/
import "C"
import (
        "fmt"
        "unsafe"
        "math/rand"
        "time"
)
func Set(key,value []byte) {
        cKey := cByteSlice(key)
        cValue := cByteSlice(value)
        C.replaceK(unsafe.Pointer(cKey),C.ulong(len(key)),unsafe.Pointer(cValue),C.ulong(len(value)))
        C.free(unsafe.Pointer(cKey))
        C.free(unsafe.Pointer(cValue))
}
func byteToChar(b []byte) *C.char {
        var c *C.char
        if len(b) > 0 {
                c = (*C.char)(unsafe.Pointer(&b[0]))
        }
        return c
}
var letterRunes = []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
func RandStringRunes(n int) []byte {
        randNum := rand.Intn(n)+1
        b := make([]byte, randNum)
        for i := range b {
                b[i] = letterRunes[rand.Intn(len(letterRunes))]
        }
        return b
}
func cByteSlice(b []byte) *C.char {
        var c *C.char
        if len(b) > 0 {
                c = (*C.char)(C.CBytes(b))
        }
        return c
}
func main() {
        rand.Seed(time.Now().UnixNano())
        var key []byte
        var value []byte
        for i:=0;i<10000000;i++ {
                key = RandStringRunes(10)
                value = RandStringRunes(20)
                randnum := 1
                if randnum == 1 {
                        fmt.Printf(">>> = %s = %s\n",key, value)
                        Set(key,value)
                }
        }
}                                                                                  

英文:

When passing golang bytes to C, the bytes length doesn't match.

The resulting strlen(key) and keylen doesnt match up.

Build with "go build file.go"

You can download the go file below here:
https://pastebin.com/raw/hnMfXJKq
<- does anyone know why my cgo call the []bytes to c has error? why the strlen doesnt match?

Expected output is supposed to be the same key length. Sometimes work, sometimes doesn't.

package main
/*
#include &lt;stddef.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;
#include &lt;stdint.h&gt;
#include &lt;string.h&gt;
#include &lt;assert.h&gt;
void replaceK(void *key, size_t keylen, void *value, size_t valuelen);
void replaceK(void *key, size_t keylen, void *value, size_t valuelen)
{
printf(&quot;replaceK : key = %s = %lu = %lu = %s = %lu\n&quot;,(char*) key,keylen,strlen(key),(char*) value,valuelen);
if (keylen != strlen(key)){
printf(&quot;ERROR!!! keylen : %lu != strlen(key) : %lu!!!\n&quot;,keylen,strlen(key));
exit(1);
}
}
*/
import &quot;C&quot;
import (
&quot;fmt&quot;
&quot;unsafe&quot;
&quot;math/rand&quot;
&quot;time&quot;
)
func Set(key,value []byte) {
cKey := cByteSlice(key)
cValue := cByteSlice(value)
C.replaceK(unsafe.Pointer(cKey),C.ulong(len(key)),unsafe.Pointer(cValue),C.ulong(len(value)))
C.free(unsafe.Pointer(cKey))
C.free(unsafe.Pointer(cValue))
}
func byteToChar(b []byte) *C.char {
var c *C.char
if len(b) &gt; 0 {
c = (*C.char)(unsafe.Pointer(&amp;b[0]))
}
return c
}
var letterRunes = []byte(&quot;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;)
func RandStringRunes(n int) []byte {
randNum := rand.Intn(n)+1
b := make([]byte, randNum)
for i := range b {
b[i] = letterRunes[rand.Intn(len(letterRunes))]
}
return b
}
func cByteSlice(b []byte) *C.char {
var c *C.char
if len(b) &gt; 0 {
c = (*C.char)(C.CBytes(b))
}
return c
}
func main() {
rand.Seed(time.Now().UnixNano())
var key []byte
var value []byte
for i:=0;i&lt;10000000;i++ {
key = RandStringRunes(10)
value = RandStringRunes(20)
randnum := 1
if randnum == 1 {
fmt.Printf(&quot;&gt;&gt;&gt; = %s = %s\n&quot;,key, value)
Set(key,value)
}
}
}                                                                                  

答案1

得分: 1

C的strlen函数用于处理以空字符结尾的字符串,而不是指针+长度形式的字符串。

你可以使用C的printf函数并使用%.*s代替%s来打印指针+长度形式的字符串。由于Go的string[]byte变量都使用指针+长度编码,这可能是从Go获取字符串后打印的正确方式。

英文:

The C strlen function is for use with null-terminated strings, not pointer+length strings.

You can print a pointer+length string with the C printf function using %.*s instead of %s. Since Go string and []byte variables both use the pointer+length encoding, that is probably the right way to print a string obtained from Go.

huangapple
  • 本文由 发表于 2021年9月12日 21:46:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/69151998.html
匿名

发表评论

匿名网友

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

确定