2014-09-28 4 views
1

Я энтузиаст Erlang и новичок Erlang Prorammer.Манипулирование бинарниками в C NIF Erlang

Мне недавно пришлось столкнуться с проблемой хруста данных в Эрланге. Поэтому я решил использовать NIF. У меня есть два списка протворцев, и я должен вернуть хеш-соединение двух пролистов на основе термина.

Чтобы реализовать это, я решил изучить двоичную манипуляцию на C. Также я использую библиотеку nifpp (C++ 11), чтобы облегчить мое обучение. Источник: https://github.com/goertzenator/nifpp

Ниже приведен код, который я могу придумать для извлечения и копирования двоичного файла в другой файл ErlNifBinary, который хорошо документирован. Но я не могу манипулировать им.

ErlNifBinary ebin, bin_term; 
nifpp::get_throws(env, argv[0], ebin); // Assigns ebin to the input binary 
enif_alloc_binary(16, &bin_term); // Size of new binary 
memcpy(bin_term.data, ebin.data, ebin.size); // Copying the contents of binary 

У меня есть указатель на unsigned char в bin_term.data. Как изменить содержимое в bin_term.data?

Кроме того, если я возвращаю существующий скопированный двоичный файл, я получаю разные выходы для одного и того же входа и не равны вводу, учитывая тот факт, что я только что обработал данные с входа. return enif_make_binary(env, &bin_term);

В Erlang РЕПЛ, если выполнить функцию с Params < < 7 >> или любой другой двоичный файл, я получаю результаты как < < 7,127,128,29,0,0,0,0,1,0 , 0,0,24,1,0,0 >> или некоторые случайные динамические значения каждый раз. Может ли кто-нибудь указать, что является ошибкой в ​​коде.

ответ

2

Прежде всего, когда вы инициализируете bin_term, вы делаете это со статическим размером 16 байт. Вот почему ваша функция всегда возвращает двоичный файл больше, чем ожидалось (16 цифр, если вы считаете). Так что первое, что вы могли бы сделать, это создать bin_term с размером двоичном передается от Erlang

enif_alloc_binary(16, &bin_term); // Constant size 

enif_alloc_binary(ebin.size, &bin_term); // Same size as binary from Erlang 

И в nifpp есть обертка на ErlNifBinary called bianry, с которым вы могли бы просто написать

binary bin_term = new binary(ebin.size); 

Или даже добавить ваш собственный конструктор копирования.

Во-вторых, это доступ к двоичным данным. Если вы посмотрите, как ErlNifBinary is defined вы можете видеть, что все данные доступны через поле data (как и ожидалось), который является указателем на unsigned char (массив другими словами, длины, заданной полем size).

Так что, если вы хотите для увеличения экземпляра и печати каждого из значений из этого двоичного файла вы могли бы сделать что-то вроде этого

ErlNifBinary ebin, bin_term; 
nifpp::get_throws(env, argv[0], ebin); // Assigns ebin to the input binary 
enif_alloc_binary(ebin.size, &bin_term); // Size of new binary 
memcpy(bin_term.data, ebin.data, ebin.size); // Copying the contents of binary 

for(int i=0; i<bin_term.size; ++i){ 
    bin_term.data[i] = bin_term.data[i] + 1; 
    std::cout << bin_term.data[i] << std::endl; 
} 

Если вам нужны другие представления данных, чем массив символов (сырой памяти), мог бы выглядеть в Resource objects, который по сути является умными указателями (собранными мусором) на вашу C-память, которые могут быть переданы в Эрланге.

+0

Большое спасибо @mpm. Также вы можете указать, как я должен хранить пролистов. – abips

+0

Если честно, я бы постарался не хранить их. Вы всегда можете переводить списки и кортежи в c-типы, но поскольку пролистники могут содержать разные кортежи длины или отдельные атомы, все это может стать очень сложным. Отправка списка ключей ключей в NIF может быть проще, если. Или, возможно, проверьте [cypto module] (http://erlang.org/doc/man/crypto.html # hash-2), в зависимости от ваших потребностей ([быстрое хеширование в C] (https://github.com/erlang/otp/blob/maint/lib/crypto/c_src/crypto.c)). – mpm

Смежные вопросы