Подтвердить что ты не робот

Ассоциативные массивы в C

Я реализую способ передачи набора данных в программируемый ключ. Ключ основан на технологии смарт-карт и может выполнять произвольный код внутри. Входные и выходные данные передаются как двоичные блоки, к которым можно получить доступ через указатели ввода и вывода.

Я хотел бы использовать ассоциативный массив для упрощения кода обработки данных. Все должно работать таким образом:

Сначала приложение-хост:

// Host application in C++
in_data["method"] = "calc_r";
in_data["id"] = 12;
in_data["loc_a"] = 56.19;
in_data["loc_l"] = 44.02;
processor->send(in_data);

Далее код внутри ключа:

// Some dongle function in C
char* method_name = assoc_get_string(in_data, "method");
int id = assoc_get_int(in_data, "id");
float loc_a = assoc_get_float(in_data, "loc_a");
float loc_l = assoc_get_float(in_data, "loc_l");

Итак, мой вопрос касается функциональности части ключа. Есть ли код или библиотека C для реализации такого поведения ассоциативного массива, как указано выше?

4b9b3361

Ответ 1

Мое подозрение в том, что вам придется писать свои собственные. Если я понимаю архитектуру, которую вы описываете, тогда вам нужно будет отправить весь фрагмент данных в одну часть. Если это так, то большинство библиотек не будут работать для этого, потому что они, скорее всего, будут выделять несколько фрагментов памяти, что потребует нескольких передач (и внутреннего понимания структуры). Это было бы похоже на попытку использования хеш-функции библиотеки, а затем отправку ее содержимого по сети в сокет, просто передав корневой указатель на функцию send.

Можно было бы написать несколько собственных утилит, которые управляют очень простым ассоциативным массивом (или хэшем) в одном блоке памяти. Если объем данных мал, он может использовать простой линейный поиск записей и будет довольно компактным битом кода.

Ответ 2

Таблица хеш-глифов. реализует интерфейс карты или (ассоциативный массив). И это, скорее всего, самая используемая реализация хеш-таблицы для C.

GHashTable *table=g_hash_table_new(g_str_hash, g_str_equal);

/* put */
g_hash_table_insert(table,"SOME_KEY","SOME_VALUE");

/* get */
gchar *value = (gchar *) g_hash_table_lookup(table,"SOME_KEY");

Ответ 3

Попробуйте uthash, библиотеку заголовков, реализующую хеш-таблицу в C. Она небольшая и довольно проста в использовании.

Ответ 4

Да, но он не будет работать так, как вы указали. Вместо этого он будет использовать struct для хранения данных и функций, которые работают с этой структурой, что даст вам нужный результат. См. Простая ассоциативная библиотека массивов в C. Пример использования:

struct map_t *test;

test=map_create();
map_set(test,"One","Won");
map_set(test,"Two","Too");
map_set(test,"Four","Fore");

Ответ 6

Марк Уилкинс дал вам правильный ответ. Если вы хотите отправить данные в виде одного фрагмента, вам нужно понять, как карты С++ представлены в вашей архитектуре и записать функции доступа.

В любом случае, если вы решили воссоздать карту на ключе, я написал небольшую библиотеку C, в которой вы могли бы написать, например:

tbl_t in_data=NULL;

tblSetSS(in_data,"method","calc_r");
tblSetSN(in_data,"id",12);
tblSetSF(in_data,"loc_a",56.19);
tblSetSF(in_data,"loc_l",44.02);

а затем:

char  *method_name = tblGetP(in_data, "method");
int    id          = tblGetN(in_data, "id");
float  loc_a       = tblGetF(in_data, "loc_a");
float  loc_l       = tblGetF(in_data, "loc_l");

Хеш-таблица - это вариация хэша Hopscotch, которая в среднем довольно хороша, и вы можете иметь любую комбинацию типа для ключей и данных (т.е. вы можете использовать целую таблицу в качестве ключа).

Фокус для этих функций заключался в облегчении программирования, а не в чистой скорости, и код не был тщательно протестирован, но если вам нравится идея и вы хотите расширить ее, вы можете посмотреть код на googlecode.

(Есть и другие вещи, такие как строки с переменной длиной строки и функция быстрого сопоставления шаблонов sttring, но в этом случае это может не представлять интереса).

Ответ 7

Binn формат сериализации является хорошим решением для передачи данных в C.

Объект binn (как объект JSON) является ассоциативным массивом. Вот пример использования:

  binn *obj;

  // create a new object
  obj = binn_object();

  // add values to it
  binn_object_set_str(obj, "method", "calc_r");
  binn_object_set_int32(obj, "id", 12);
  binn_object_set_float(obj, "loc_a", 56.19);
  binn_object_set_float(obj, "loc_l", 44.02);

  // send over the network
  send(sock, binn_ptr(obj), binn_size(obj));

  // release the buffer
  binn_free(obj);

И читать:

  char* method_name = binn_object_str(obj, "method");
  int   id    = binn_object_int32(obj, "id");
  float loc_a = binn_object_float(obj, "loc_a");
  float loc_l = binn_object_float(obj, "loc_l");

Это всего лишь 2 файла (binn.c и binn.h), поэтому он может быть скомпилирован в проекте вместо использования в качестве общей библиотеки.

Но я не знаю, может ли он поместиться в ключ.

Ответ 8

Это старый поток, но я думал, что это может быть полезно для тех, кто ищет реализацию. Это не занимает слишком много кода; Я сделал это в ~ 100 строках без дополнительной библиотеки. Я назвал его словарем, поскольку он параллелирует (вроде) тип данных python. Вот мой код:

#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>

typedef struct hollow_list hollow_list;

struct hollow_list{
    unsigned int size;
    void *value;
    bool *written;
    hollow_list *children;
};

//Creates a hollow list and allocates all of the needed memory
hollow_list hollow_list_create(unsigned int size){
    hollow_list output;
    output = (hollow_list) {.size = size, .value = (void *) 0, .written = calloc(size, sizeof(bool)), .children = calloc(size, sizeof(hollow_list))};
    return output;
}

//Frees all memory of associated with a hollow list and its children
void hollow_list_free(hollow_list *l, bool free_values){
    int i;
    for(i = 0; i < l->size; i++){
        hollow_list_free(l->children + i, free_values);
    }
    if(free_values){
        free(l->value);
    }
    free(l);
}

//Reads from the hollow list and returns a pointer to the item data
void *hollow_list_read(hollow_list *l, unsigned int index){
    if(index == 0){
        return l->value;
    }
    unsigned int bit_checker;
    bit_checker = 1<<(l->size - 1);
    int i;
    for(i = 0; i < l->size; i++){
        if(bit_checker & index){
            if(l->written[i] == true){
                return hollow_list_read(l->children + i, bit_checker ^ index);
            } else {
                return (void *) 0;
            }
        }
        bit_checker >>= 1;
    }
}

//Writes to the hollow list, allocating memory only as it needs
void hollow_list_write(hollow_list *l, unsigned int index, void *value){
    if(index == 0){
        l->value = value;
    } else {
        unsigned int bit_checker;
        bit_checker = 1<<(l->size - 1);
        int i;
        for(i = 0; i < l->size; i++){
            if(bit_checker & index){
                if(!l->written[i]){
                    l->children[i] = hollow_list_create(l->size - i - 1);
                    l->written[i] = true;
                }
                hollow_list_write(l->children + i, bit_checker ^ index, value);
                break;
            }
            bit_checker >>= 1;
        }
    }
}

typedef struct dictionary dictionary;

struct dictionary{
    void *value;
    hollow_list *child;
};

dictionary dictionary_create(){
    dictionary output;
    output.child = malloc(sizeof(hollow_list));
    *output.child = hollow_list_create(8);
    output.value = (void *) 0;
    return output;
}

void dictionary_write(dictionary *dict, char *index, unsigned int strlen, void *value){
    void *hollow_list_value;
    dictionary *new_dict;
    int i;
    for(i = 0; i < strlen; i++){
        hollow_list_value = hollow_list_read(dict->child, (int) index[i]);
        if(hollow_list_value == (void *) 0){
            new_dict = malloc(sizeof(dictionary));
            *new_dict = dictionary_create();
            hollow_list_write(dict->child, (int) index[i], new_dict);
            dict = new_dict;
        } else {
            dict = (dictionary *) hollow_list_value;
        }
    }
    dict->value = value;
}

void *dictionary_read(dictionary *dict, char *index, unsigned int strlen){
    void *hollow_list_value;
    dictionary *new_dict;
    int i;
    for(i = 0; i < strlen; i++){
        hollow_list_value = hollow_list_read(dict->child, (int) index[i]);
        if(hollow_list_value == (void *) 0){
            return hollow_list_value;
        } else {
            dict = (dictionary *) hollow_list_value;
        }
    }
    return dict->value;
}

int main(){
    char index0[] = "hello, this is a test";
    char index1[] = "hello, this is also a test";
    char index2[] = "hello world";
    char index3[] = "hi there!";
    char index4[] = "this is something";
    char index5[] = "hi there";

    int item0 = 0;
    int item1 = 1;
    int item2 = 2;
    int item3 = 3;
    int item4 = 4;

    dictionary d;
    d = dictionary_create();
    dictionary_write(&d, index0, 21, &item0);
    dictionary_write(&d, index1, 26, &item1);
    dictionary_write(&d, index2, 11, &item2);
    dictionary_write(&d, index3, 13, &item3);
    dictionary_write(&d, index4, 17, &item4);

    printf("%d\n", *((int *) dictionary_read(&d, index0, 21)));
    printf("%d\n", *((int *) dictionary_read(&d, index1, 26)));
    printf("%d\n", *((int *) dictionary_read(&d, index2, 11)));
    printf("%d\n", *((int *) dictionary_read(&d, index3, 13)));
    printf("%d\n", *((int *) dictionary_read(&d, index4, 17)));
    printf("%d\n", ((int) dictionary_read(&d, index5, 8)));
}

К сожалению, вы не можете реплицировать синтаксис списка [x], но это лучшая альтернатива, с которой я столкнулся.