gpt4 book ai didi

julia - 如何将 `Ptr` 获取到 `NTuple` 的元素?

转载 作者:行者123 更新时间:2023-12-03 16:13:52 25 4
gpt4 key购买 nike

假设我有一个元组 Cchar

str = ('f', 'o', 'o', '\0', '\0')

我想将其转换为更传统的字符串。如果 strVector ,我可以创建 Ptr并用它做各种各样的事情。我尝试了各种传递方式 strpointer 的方法, Ptr , Ref , 和 unsafe_string没有成功,因为那些通常在数组而不是元组上工作。有什么建议么?

注意:我真正拥有的是一个看起来像的 C 结构
typedef struct foo {
char str[FOO_STR_MAX_SZ];
...
} foo_t;

其中 Clang.jl 包装为
struct foo_t
str :: NTuple{FOO_STR_MAX_SZ, UInt8}
...
end

我也玩过 NTupleCchar (即 Int8 )而不是 UInt8 ,我尝试使用 SVector而不是 NTuple也是。但我仍然找不到生成 Ptr 的方法来自 str field 。我错过了什么吗?

最佳答案

既然你问了这个问题,我想把它收集到一个数组 a = collect(x.str)不是你期待的答案...

您可以使用 ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), a)获取a的指针即使a是不可变的。但是,一味地使用它会产生一些令人困惑的结果:

julia> struct foo_t
str::NTuple{2, UInt8}
end

julia> a = foo_t((2, 3))
foo_t((0x02, 0x03))

julia> ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), a.str)
Ptr{Nothing} @0x00007f4302c4f670

julia> ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), a.str)
Ptr{Nothing} @0x00007f4302cc47e0

我们从同一个对象中得到了两个不同的指针!原因是因为 NTuple是不可变的,编译器会为它做很多“优化”,例如,每次使用时都要应对。这就是为什么在 source code 中明确禁止从不可变对象(immutable对象)获取指针的原因。 :
function pointer_from_objref(@nospecialize(x))
@_inline_meta
typeof(x).mutable || error("pointer_from_objref cannot be used on immutable objects")
ccall(:jl_value_ptr, Ptr{Cvoid}, (Any,), x)
end

但是,有几种解决方法。首先,由于表达式 a.str复制元组,你可以避开这个表达式,直接使用 a的地址计算它的地址和 fieldoffset(typeof(a), 1) . (1 表示 strfoo_t 的第一个字段)
julia> p = Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), a)) + fieldoffset(typeof(a), 1)
Ptr{UInt8} @0x00007f4304901df0

julia> p2 = Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), a)) + fieldoffset(typeof(a), 1)
Ptr{UInt8} @0x00007f4304901df0

julia> p === p2
true

julia> unsafe_store!(p, 5)
Ptr{UInt8} @0x00007f4304901df0

julia> a
foo_t((0x05, 0x03))

现在可以了。但是,仍然有一些警告:当您尝试将代码包装在一个函数中时,它再次出错了:
julia> mut!(a) = unsafe_store!(Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), a)) + fieldoffset(typeof(a), 1), 8)
mut! (generic function with 1 method)

julia> mut!(a)
Ptr{UInt8} @0x00007f42ec560294

julia> a
foo_t((0x05, 0x03))
a没有改变,因为, foo_t本身也是不可变的,将被复制到 mut! ,因此在函数内部所做的更改将不会在外部可见。为了解决这个问题,我们需要包装 a在一个可变对象中给它一个稳定的堆地址。 Base.RefValue可用于此目的:
julia> b = Base.RefValue(a)
Base.RefValue{foo_t}(foo_t((0x05, 0x03)))

julia> mut!(b) = unsafe_store!(Ptr{UInt8}(ccall(:jl_value_ptr, Ptr{UInt8}, (Any,), b)) + fieldoffset(typeof(b), 1) + fieldoffset(typeof(a), 1), 8)
mut! (generic function with 1 method)

julia> mut!(b)
Ptr{UInt8} @0x00007f43057b3820

julia> b
Base.RefValue{foo_t}(foo_t((0x08, 0x03)))

julia> b[]
foo_t((0x08, 0x03))

关于julia - 如何将 `Ptr` 获取到 `NTuple` 的元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54889057/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com