将C字符串转换为Go字符串而不使用CGO。

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

Convert C string to Go string without CGO

问题

我正在使用Go Windows syscall库从DLL中的函数中获取数据。这一切都很顺利,但是我无法找到一种方法将LPCTSTR(指向C字符串的指针)转换为适当的Go字符串,而不使用CGO。

如果可能的话,我想尽量避免使用CGO,因为在Windows上,CGO代码的两个选项(交叉编译和在Windows上安装gcc)仍然相当复杂。

英文:

I'm using the Go Windows syscall libraries to get data out of a function in a DLL. This all works great, but I can't figure out a way to convert a LPCTSTR (pointer to C String) into a proper Go string without using CGO.

I'd like to avoid CGO if at all possible, because the two options for CGO code on Windows (cross-compiling, and installing gcc on windows) are still fairly complex.

答案1

得分: 3

如果你有一个8位字符串,你可以将LPCTSTR指针转换为正确大小的[]byte,并将其复制到一个新的字符串或切片中。

a := (*[1 << 30-1]byte)(unsafe.Pointer(lpctstr))
size := bytes.IndexByte(a[:], 0)
// 如果你只想要一个字符串
// goString := string(a[:size:size])

// 如果你想要一个指向原始内存位置的切片而不进行复制
// goBytes := a[:size:size]

goBytes := make([]byte, size)
copy(goBytes, a)

如果LPCTSTR指向包含16位Unicode字符的LPCWSTR,你可以使用utf16包进行转换。

a := (*[1 << 30-1]uint16)(unsafe.Pointer(lpctstr))
size := 0
for ; size < len(a); size++ {
    if a[size] == uint16(0) {
        break
    }
}   
runes := utf16.Decode(a[:size:size])
goString := string(runes)
英文:

If you have an 8 bit string, you can convert the LPCTSTR pointer to a []byte of the proper size, and copy it to a new string or slice.

a := (*[1 &lt;&lt; 30-1]byte)(unsafe.Pointer(lpctstr))
size := bytes.IndexByte(a[:], 0)
// if you just want a string
// goString := string(a[:size:size])

// if you want a slice pointing to the original memory location without a copy
// goBytes := a[:size:size]

goBytes := make([]byte, size)
copy(goBytes, a)

If the LPCTSTR points to an LPCWSTR which contains 16bit unicode characters, you can convert that with the utf16 package.

a := (*[1 &lt;&lt; 30-1]uint16)(unsafe.Pointer(lpctstr))
size := 0
for ; size &lt; len(a); size++ {
    if a[size] == uint16(0) {
        break
    }
}   
runes := utf16.Decode(a[:size:size])
goString := string(runes)

答案2

得分: 1

如果您可以在没有CGO的情况下获得指向C字符串的指针,并且还可以获得字符串的长度,那么您可以首先从C字符串创建一个字节切片。

import (
	"reflect"
	"unsafe"
)

func ToByteSlice() []byte {
	var bytes []byte

	shdr := (*reflect.SliceHeader)(unsafe.Pointer(&bytes))
	shdr.Cap = int(stringlen)
	shdr.Len = int(stringlen)
	shdr.Data = uintptr(unsafe.Pointer(cpointer))

	return bytes
}

这段代码将创建一个字节切片 bytes,并使用 reflect.SliceHeader 将其与 C 字符串关联起来。然后,将字符串的长度和指针分别赋值给 shdr.Lenshdr.Data。最后,返回字节切片 bytes

英文:

If you can get a pointer to a cstring without CGO, and you can get the length of the string too, then perhaps you should create a byte slice from the cstring first.

import (
	&quot;reflect&quot;
	&quot;unsafe&quot;
)

func ToByteSlice() []byte {
	var bytes []byte

	shdr := (*reflect.SliceHeader)(unsafe.Pointer(&amp;bytes))
	shdr.Cap = int(stringlen)
	shdr.Len = int(stringlen)
	shdr.Data = uintptr(unsafe.Pointer(cpointer))

	return bytes
}

huangapple
  • 本文由 发表于 2016年12月22日 00:03:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/41267069.html
匿名

发表评论

匿名网友

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

确定