2016-11-07 6 views
3

Мой вопрос прост, но я не знаю, как это сделать (или Julia не предлагает такого способа на данный момент): как установить поле значение C struct от Julia?Обновление значения поля C struct от Julia

Представьте, что вы есть тип структуры для представления узла дерева в библиотеке C:

typedef struct node_s 
{ 
    int type; 
    node_t* next; 
    node_t* children; 
    node_t* parent; 
} node_t; 

и скопировать его в Джулии:

immutable node_t 
    typ::Cint 
    next::Ptr{node_t} 
    children::Ptr{node_t} 
    parent::Ptr{node_t} 
end 

Теперь предположим, что у вас есть указатель на node_t выделено в C и хотите обновить поле parent в Джулии. Я знаю, что у нас есть unsafe_store!, чтобы обновить значение, указанное указателем, но громоздко вычислить смещение указателя поля parent (в этом случае это будет sizeof(Int) + sizeof(Ptr{node_t}) * 2 на моей 64-битной машине). Есть ли более простой способ сделать то же самое?

ответ

5

fieldoffset функция предусмотрена для этого случая использования:

julia> immutable node_t 
      typ::Cint 
      next::Ptr{node_t} 
      children::Ptr{node_t} 
      parent::Ptr{node_t} 
     end 

julia> fieldoffset(node_t, 1) 
0x0000000000000000 

julia> fieldoffset(node_t, 2) 
0x0000000000000008 

julia> fieldoffset(node_t, 3) 
0x0000000000000010 

julia> fieldoffset(node_t, 4) 
0x0000000000000018 

Но и не быть обеспокоены просто хранить всю immutable, с одно поле изменилось; он будет оптимизирован.

julia> k = Ptr{node_t}(Libc.malloc(sizeof(node_t))) 
Ptr{node_t} @0x00000000036194c0 

julia> unsafe_load(k) 
node_t(29544064,Ptr{node_t} @0x3038662d34363a34,Ptr{node_t} @0x3a386e2d3832313a,Ptr{node_t} @0x34363a32333a3631) 

julia> update_parent(x::node_t, n::Ptr{node_t}) = 
      node_t(x.typ, x.next, x.children, n) 
update_parent (generic function with 1 method) 

julia> mutate!(k) = unsafe_store!(k, update_parent(unsafe_load(k), Ptr{node_t}(0))) 
mutate! (generic function with 1 method) 

julia> @code_llvm mutate!(k) 

define %node_t* @"julia_mutate!_70963"(%node_t*) #0 { 
top: 
    %1 = load %node_t, %node_t* %0, align 1 
    %.fca.3.insert = insertvalue %node_t %1, %node_t* null, 3 
    store %node_t %.fca.3.insert, %node_t* %0, align 1 
    ret %node_t* %0 
} 
+0

Отличный ответ! Я не знал 'fieldoffset', и такая оптимизация работает очень хорошо. Большое спасибо!. – bicycle1885