web-dev-qa-db-fra.com

Tableaux associatifs en C

J'implémente un moyen de transférer un ensemble de données vers un dongle programmable. Le dongle est basé sur une technologie de carte à puce et peut exécuter un code arbitraire à l'intérieur. Les données d'entrée et de sortie sont transmises sous forme de blocs binaires accessibles via des pointeurs d'entrée et de sortie.

Je souhaite utiliser un tableau associatif pour simplifier le code informatique. Tout devrait fonctionner de cette façon:

Tout d'abord l'application hôte:

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

Ensuite, le code à l'intérieur du 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");

Ma question porte donc sur la fonctionnalité de la pièce du dongle. Existe-t-il du code C ou une bibliothèque pour implémenter un tel comportement de tableau associatif comme ci-dessus?

42
ezpresso

Je soupçonne que vous devrez écrire le vôtre. Si je comprends l'architecture que vous décrivez, vous devrez envoyer le bloc de données entier en une seule pièce. Si c'est le cas, la plupart des bibliothèques ne fonctionneront pas pour cela car elles alloueront probablement plusieurs morceaux de mémoire, ce qui nécessiterait plusieurs transferts (et une compréhension interne de la structure). Cela reviendrait à essayer d'utiliser une fonction de hachage de bibliothèque, puis à envoyer son contenu sur le réseau sur un socket en passant simplement le pointeur racine à la fonction send.

Il serait possible d'écrire certains de vos propres utilitaires qui gèrent un tableau associatif (ou hachage) très simple dans un seul bloc de mémoire. Si la quantité de données est petite, elle pourrait utiliser une simple recherche linéaire pour les entrées et serait un morceau de code assez compact.

10
Mark Wilkins

table de hachage de Glib. implémente une interface de carte ou (tableau associatif). Et c'est probablement l'implémentation de table de hachage la plus utilisée pour 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");
22
Manuel Salvadores

Essayez thash , une bibliothèque d'en-tête implémentant une table de hachage en C. Elle est petite et assez facile à utiliser.

10
Hasturkun

Oui, mais cela ne fonctionnera pas de la manière que vous avez spécifiée. Il utilisera à la place un struct pour stocker les données et les fonctions qui opèrent sur cette structure, vous donnant le résultat souhaité. Voir ne bibliothèque de tableaux associatifs simples en C . Exemple d'utilisation:

struct map_t *test;

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

GLib's Hash Tables et Balanced Binary Trees pourrait être ce que vous recherchez.

2
Matt Joiner

C'est un vieux fil de discussion, mais je pensais que cela pourrait encore être utile pour quiconque cherche une implémentation. Cela ne prend pas trop de code; J'ai fait le mien en ~ 100 lignes sans aucune bibliothèque supplémentaire. Je l'ai appelé un dictionnaire car il est parallèle (en quelque sorte) au type de données python. Voici mon 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)));
}

Malheureusement, vous ne pouvez pas reproduire la syntaxe de la liste [x], mais c'est la meilleure alternative que j'ai trouvée.

2
2.71828-asy

Mark Wilkins vous a donné la bonne réponse. Si vous souhaitez envoyer les données en tant que bloc unique, vous devez comprendre comment les cartes C++ sont représentées dans votre architecture et écrire les fonctions d'accès.

Quoi qu'il en soit, si vous décidez de recréer la carte sur le dongle, j'ai écrit une petite bibliothèque C où vous pourriez écrire des idées comme:

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

puis:

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

La table de hachage est une variation du hachage Hopscotch, qui est plutôt bonne en moyenne, et vous pouvez avoir n'importe quel mélange de types pour les clés et les données (c'est-à-dire que vous pouvez utiliser une table entière comme clé).

L'objectif de ces fonctions était de faciliter la programmation plutôt que la vitesse pure et le code n'est pas complètement testé, mais si vous aimez l'idée et que vous souhaitez la développer, vous pouvez jeter un œil au code sur googlecode .

(Il y a d'autres choses comme des chaînes de longueur variable et une fonction de correspondance de modèle de chaîne rapide mais celles-ci pourraient ne pas être intéressantes dans ce cas).

2
Remo.D