【问题标题】:Access the raw bytes of a string访问字符串的原始字节
【发布时间】:2018-03-28 03:51:59
【问题描述】:

我正在尝试调用一个 C 函数,该函数需要来自 go 的 C 字符串 (char*)。我知道cgo documentation 中记录的C.CString 函数,但由于我正在调用的函数已经制作了一个副本,我试图避免使用Cstring 制作的那个。

现在,我正在这样做,s 是一个 go 字符串

 var cs *C.char = (*C.char)( unsafe.Pointer(& []byte(s) [0]))

但我感觉[]bytes(s) 正在制作自己的副本。是否有可能只获得 char*

【问题讨论】:

标签: go cgo


【解决方案1】:

如果您执行此操作的次数足够多,以至于担心性能问题,那么最好一开始就将数据保存在一个切片中。

如果你真的想访问字符串的地址,可以使用unsafe包将其转换为与字符串头匹配的struct。使用reflect.StringHeader 类型:

p := unsafe.Pointer((*(*reflect.StringHeader)(unsafe.Pointer(&s))).Data)

或者使用切片作为代理,因为它们都将数据指针和长度整数放在相同的字段位置

p := unsafe.Pointer(&(*(*[]byte)(unsafe.Pointer(&s)))[0])

或者因为数据指针在前,你可以单独使用uintptr

p := unsafe.Pointer(*(*uintptr)(unsafe.Pointer(&s)))

https://play.golang.org/p/ps1Py7Ax6QK

这些方法都不能保证在所有情况下都有效,或者在 Go 的未来版本中有效,并且没有任何选项可以保证以空值结尾的字符串。

受支持的最佳选项是在 cgo 序言中创建一个 shim 以接受 go 字符串,并将其转换为 *char。 CGO 提供对以下功能的访问:

const char *_GoStringPtr(_GoString_ s);

请参阅文档中的Go references to C 部分。

【讨论】:

  • 不确定这是否适用,但the release notes of 1.10 提到以下内容:«Cgo 现在支持从 C 直接访问 Go 字符串值。C 前导码中的函数可以使用类型 _GoString_ 来接受将字符串作为参数。 C 代码可以调用_GoStringLen_GoStringPtr 来直接访问字符串的内容。 _GoString_ 类型的值可以在调用导出的 Go 函数时传递,该函数接受 Go 类型字符串的参数。»
  • @kostix:是的,我差点忘了!这直接回答了将数据转换为*char 的问题,但是插入一个 shim 来处理 GoString 类型将是最佳的
  • 谢谢。提供一点背景知识,这是在 R 和 go 之间架起一座桥梁的一部分,所以有时我需要想办法将 go 字符串切片移动到 R 字符向量中。
  • 谢谢@kostix,如果你愿意,我会接受这个答案。
  • @RomainFrancois 谢谢,我对 JimB 的更新答案很满意 :-)
猜你喜欢
  • 2013-03-20
  • 1970-01-01
  • 1970-01-01
  • 2021-12-30
  • 1970-01-01
  • 1970-01-01
  • 2020-07-09
  • 1970-01-01
  • 2018-04-14
相关资源
最近更新 更多