简体   繁体   English

C 中的关联数组

[英]Associative arrays in C

I am implementing a way to transfer a set of data to a programmable dongle.我正在实施一种将一组数据传输到可编程加密狗的方法。 The dongle is based on a smart card technology and can execute an arbitrary code inside.加密狗基于智能卡技术,可以在内部执行任意代码。 The input and output data is passed as a binary blocks that can be accessed via input and output pointers.输入和输出数据作为二进制块传递,可以通过输入和输出指针访问。

I would like to use an associative array to simplify the data processing code.我想使用关联数组来简化数据处理代码。 Everything should work this way:一切都应该这样工作:

First the host application:首先是主机应用程序:

// 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);

Next the code inside the dongle:接下来是加密狗内的代码:

// 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");

So my question is about the dongle part functionality.所以我的问题是关于加密狗部分的功能。 Is there C code or library to implement such an associative array behavior like the above?是否有 C 代码或库来实现像上面这样的关联数组行为?

Glib's hash table. Glib 的哈希表。 implements a map interface or (associative array).实现映射接口或(关联数组)。 And it's most likely the most used hash table implementation for C.它很可能是 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");

My suspicion is that you would have to write your own.我的怀疑是你必须自己写。 If I understand the architecture you are describing, then you will need to send the entire chunk of data in a single piece.如果我理解您所描述的架构,那么您将需要将整个数据块发送到一个单独的部分。 If so, then most libraries will not work for that because they will most likely be allocating multiple pieces of memory, which would require multiple transfers (and an inside understanding of the structure).如果是这样,那么大多数库都不会为此工作,因为它们很可能会分配多块内存,这将需要多次传输(以及对结构的内部理解)。 It would be similar to trying to use a library hash function and then sending its contents over the network on a socket just by passing the root pointer to the send function.这类似于尝试使用库哈希函数,然后仅通过将根指针传递给send函数,通过套接字在网络上发送其内容。

It would be possible to write some utilities of your own that manage a very simple associative array (or hash) in a single block of memory.可以编写一些自己的实用程序,在单个内存块中管理一个非常简单的关联数组(或散列)。 If the amount of data is small, it could use a simple linear search for the entries and would be a fairly compact bit of code.如果数据量很小,它可以对条目使用简单的线性搜索,这将是一段相当紧凑的代码。

试试uthash ,这是一个在 C 中实现哈希表的头库。它很小而且很容易使用。

This is an old thread, but I thought this might still be useful for anyone out there looking for an implementation.这是一个旧线程,但我认为这对于寻找实现的人来说可能仍然有用。 It doesn't take too much code;不需要太多代码; I did mine in ~100 lines of without any extra library.我在没有任何额外库的情况下用了大约 100 行。 I called it a dictionary since it parallels (sort of) the python datatype.我称它为字典,因为它与(某种)python 数据类型平行。 Here is my code:这是我的代码:

#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's 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)));
}

Unfortunately you can't replicate the list[x] syntax, but this is the best alternative I have come up with.不幸的是,您无法复制 list[x] 语法,但这是我提出的最佳替代方案。

Yes, but it will not work in the way you have specified.是的,但它不会按照您指定的方式工作。 It will instead use a struct to store the data and functions that operate on that struct, giving you the result you want.相反,它将使用一个struct来存储对该struct进行操作的数据和函数,从而为您提供所需的结果。 See A Simple Associative Array Library In C .请参阅C 中的简单关联数组库 Example of use:使用示例:

struct map_t *test;

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

GLib 的哈希表平衡二叉树可能正是您所追求的。

Mark Wilkins gave you the right answer.马克威尔金斯给了你正确的答案。 If you want to send the data as a single chunk, you need to understand how C++ maps are represented in your architecture and write the access functions.如果您想将数据作为单个块发送,您需要了解 C++ 映射在您的架构中如何表示并编写访问函数。

Anyway, if you decide to recreate the map on the dongle, I've written a small C library where you could write thinks like:无论如何,如果您决定在加密狗上重新创建地图,我已经编写了一个小型 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);

and then:进而:

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");

The hashtable is a variation of the Hopscotch hash, which is rather good on average, and you can have any mix of type for keys and data (ie you can use an entire table as a key).散列表是 Hopscotch 散列的变体,平均而言相当不错,您可以将任何类型的键和数据混合在一起(即您可以使用整个表作为键)。

The focus for that functions was on easing programming rather than pure speed and the code is not thoroughly tested but if you like the idea and want to expand on it, you can have a look at the code on googlecode .该功能的重点是简化编程而不是纯粹的速度,并且代码没有经过彻底测试,但是如果您喜欢这个想法并想要扩展它,您可以查看googlecode上的代码。

(There are other things like variable length strings and a fast sttring pattern matching function but those might not be of interest in this case). (还有其他东西,如可变长度字符串和快速字符串模式匹配函数,但在这种情况下可能不感兴趣)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM