Управление двоичными файлами в C NIF Erlang

Я энтузиаст Erlang и новичок в Erlang Prorammer.

Недавно мне пришлось столкнуться с проблемой обработки данных в 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

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

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

В erlang REPL, если я выполняю функцию с параметрами ‹‹7>> или любым другим двоичным файлом, я получаю результаты как ‹‹7,127,128,29,0,0,0,0,1,0,0,0,24. ,1,0,0>> или несколько случайных динамических значений каждый раз. Может кто-нибудь указать, в чем ошибка в коде.


person abips    schedule 28.09.2014    source источник


Ответы (1)


Прежде всего, когда вы инициализируете 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 под названием bianry, с которой вы мог просто написать

binary bin_term = new binary(ebin.size);

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

Во-вторых, это доступ к двоичным данным. Если вы посмотрите, как определяется ErlNifBinary вы можете видеть, что все данные доступны через поле 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;
}

Если вам нужно другое представление данных, кроме массива символов (необработанная память), вы можете заглянуть в объекты ресурсов. которые, по сути, являются умными указателями (собранным мусором) на вашу C-память, которые можно передавать в Erlang.

person mpm    schedule 28.09.2014
comment
Большое спасибо @mpm. Также вы можете указать, как мне хранить пролисты. - person abips; 28.09.2014
comment
Честно говоря, я бы попробовал их не хранить. Вы всегда можете преобразовать списки и кортежи в c-типы, но поскольку пролисты могут содержать кортежи разной длины или отдельные атомы, все может стать очень сложным. Отправка только списка ключей в NIF может быть проще, если. Или проверьте модуль шифрования, в зависимости от ваших потребностей (быстрое хеширование в C). - person mpm; 28.09.2014