Golang中cmd/cgo无法使用cgo函数创建文件:文件名编码无效问题
Golang中cmd/cgo无法使用cgo函数创建文件:文件名编码无效问题 请先回答以下问题再提交问题。谢谢!
你使用的 Go 版本是什么(go version)?
go1.10.2 linux/amd64
这个问题在最新版本中是否仍然存在?
不确定,没有在我现有版本之上的版本中测试过
你使用的操作系统和处理器架构是什么(go env)?
GOHOSTARCH=“amd64” GOHOSTOS=“linux”
你做了什么?
我尝试将一个 Go 程序转换为共享库,以便在 R 脚本中使用。最初我用一个简单的功能进行测试:一个接收输入路径(字符串)并在磁盘上创建文件的函数。我的问题是,包含路径的字符串变成了某种无效编码的内容,如下所示:
如果可能,请提供重现错误的步骤。 一个完整的可运行程序更好。 在 play.golang.org 上的链接最佳。
这是我的函数:
import "C"
(...)
//export testWriter
func testWriter(path string) string {
file, err := os.Create(path)
if err != nil {
return "error"
}
defer file.Close()
return path
}
我用以下命令编译库:
go build -o gowriter.so -buildmode=c-shared ./gowriter
然后我这样运行我的 R 脚本:
Rscript -e 'dyn.load("/home/user/go/src/github.com/user/gowriter.so"); .Call("testWriter", "/home/user/test.txt")'
我还尝试在 Python 程序中运行:
from ctypes import *
lib = cdll.LoadLibrary("/home/user/go/src/github.com/prvst/testwriter.so")
lib.testReader("/home/user/test.txt")
我得到的是一个名为 �(无效编码) 的文件。这字面意思就是文件名,包括你看到的那里的感叹号符号。
我添加了一些打印函数来尝试理解问题,这是我得到的结果:
fmt.Println(reflect.TypeOf(path)) # string
fmt.Println(reflect.TypeOf(C.CString(path))) # *main._Ctype_char
fmt.Println(C.CString(path)) # 0x559b609e1210
我还尝试了这个但没有成功:
func testWriter(path *C.char) *C.char {
file, err := os.Create(C.GoString(path))
if err != nil {
return C.CString("error")
}
defer file.Close()
return path
}
我觉得奇怪的是,函数在返回语句处结束,我可以在终端上看到传递给函数的正确路径字符串。
你期望看到什么?
在我的磁盘上看到一个名为 test.txt 的空文件
你实际看到了什么?
在我的磁盘上看到一个名为 �(无效编码) 的空文件
更多关于Golang中cmd/cgo无法使用cgo函数创建文件:文件名编码无效问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我虽然没有这方面的具体经验,但这听起来像是源于Go语言的UTF-8编码标准。或许可以使用utf8 C语言库来解析?
// 代码示例
func main() {
fmt.Println("hello world")
}
更多关于Golang中cmd/cgo无法使用cgo函数创建文件:文件名编码无效问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
根据你的描述,问题出现在Go与C之间字符串编码的转换上。当Go字符串通过cgo传递给C时,需要使用正确的转换函数。你的第二个尝试方向是正确的,但需要确保字符串在Go和C之间正确传递。
以下是修复后的代码:
package main
/*
#include <stdlib.h>
*/
import "C"
import (
"os"
"unsafe"
)
//export testWriter
func testWriter(path *C.char) *C.char {
// 将C字符串转换为Go字符串
goPath := C.GoString(path)
file, err := os.Create(goPath)
if err != nil {
// 返回错误信息,需要分配新的C字符串
errMsg := C.CString("error: " + err.Error())
return errMsg
}
defer file.Close()
// 返回原始路径,不需要重新分配
return path
}
func main() {
// 空main函数,构建共享库时需要
}
关键点说明:
- 函数签名必须使用C类型:
*C.char而不是Go的string - 使用
C.GoString()将C字符串转换为Go字符串 - 返回字符串时,如果返回新的字符串内容,需要使用
C.CString()分配内存 - 如果返回输入的原始路径,可以直接返回
path参数
编译命令:
go build -o gowriter.so -buildmode=c-shared ./gowriter
在R中的调用方式:
dyn.load("/home/user/go/src/github.com/user/gowriter.so")
result <- .Call("testWriter", "/home/user/test.txt")
在Python中的调用方式:
from ctypes import *
lib = cdll.LoadLibrary("/home/user/go/src/github.com/prvst/gowriter.so")
lib.testWriter.argtypes = [c_char_p]
lib.testWriter.restype = c_char_p
result = lib.testWriter(b"/home/user/test.txt")
print(result.decode('utf-8'))
注意在Python中需要正确设置参数类型和返回类型,并使用字节字符串(b"string")传递路径。
这个修复应该能解决文件名编码无效的问题,正确创建名为"test.txt"的文件。

