[gelöst] Beschränkter Zugriff auf Strukt



  • Hi!

    Ich habe ein Strukt "RhymePair", das zwei Wörter enthält, die sich reimen. Da es keinen Zustand geben darf, in dem sich die Wörter nicht reimen, soll der Benutzer ein neues Strukt RhymePair mit zwei Wörtern nur über eine Funktion erzeugen dürfen. Er darf dann also das Strukt selber nicht sehen ?!? Das geht ja aber nicht, weil er mit dem Datentyp ja arbeiten muss.

    Wie ich krieg ich sowas in C hin? Privat und public o.ä. gibt es ja in C nicht.



  • du könntest dir getter und setter functionen bauen? denen du einen void* datentyp übergibst innerhalb der function castest du void* in RhymePair* und kannst dann damit arbeiten natürlich kann man void* auch noch bearbeiten aber ohne die structur zu kennen ist es schon etwas schwerer, aber was besserers fällt mir jetzt nicht ein 😞



  • Forward declaration in den Header den der Nutzer benutzen soll, Definition und zugehörige Funktionen/Methoden dann in das .c

    http://en.wikipedia.org/wiki/Forward_declaration

    Edit: Das hat natürlich nicht nur Vorteile. Ich persönlich bin eh kein übergroßer Freund davon den Inhalt von Strukturen zu verstecken (was auch irgendwie albern ist wenn man eh triviale getter/setter hat). Vielmehr sollte man durch das Anbieten einer sinnvollen Schnittstelle das wilde Ändern in "privaten" Strukturen unattraktiv machen. Frickler und sonstige Experten hält das natürlich nicht auf, aber gerade die sollen ja auf die Schnauze fallen 😉



  • Nutzer haben mit Structs nichts zu tun, das wären wenn dann Programmierer. Und bei Programmierern kannst du einen Kommentar ranschreiben wo steht "Die Wörter müssen sich reimen". Wenn sich der Programmierer nicht dran hält wird irgendwas nicht funktionieren.

    Du kannst allerdings erzwingen dass der Programmierer die Struktur nicht sehen kann indem du eine extra C-Datei nimmst, dort die üblicher Konstruktoren, Destruktoren, Getter und Setter schreibst und den Rest static machst. Das bedeutet es ist nur innerhalb dieser C-Datei sichtbar. Du musst natürlich jedes mal 2 Wörter übergeben und nie die Struktur.
    Spätestens wenn du die C-Datei in eine Objektdatei vorkompilierst wird es anstrengend bzw. nutzlos an die Struktur ranzukommen.

    Du solltest dir aber genau überlegen ob du die Programmierer so ärgern willst. Es gibt einen Unterschied zwischen Kapselung und Schikane.



  • Du kannst (ähnlich wie nwp2 beschreibt) private Elemente emulieren, folgendes wird z.B. in GTK+ gemacht: (beachte die Dateinamen)

    /* RhymePair.h */
    
    struct RhymePair {
        /* public */
        int id;
        ...
        /* private */
        void *private;
    };
    
    ...
    
    /* RhymePair.c */
    
    #include <RhymePair.h>
    
    struct RhymePairPrivate {
        char *word1;
        char *word2;
    };
    
    struct RhymePair *rhyme_pair_new(void)
    {
        struct RhymePair *tmp;
        struct RhymePairPrivate *priv_tmp;
    
        tmp = calloc(1, sizeof *tmp);
        if(tmp == NULL)
            return NULL;
    
        /* tmp initialisieren */
    
        priv_tmp = calloc(1, sizeof *priv_tmp);
        if(priv_tmp)
        {
             free(tmp);
             return NULL;
        }
    
        tmp->private = priv_tmp;
        return tmp;
    }
    
    rhyme_pair_set_words(struct RhymePair *rp, const char *w1, const char *w2)
    {
        ...
        struct RhymePairPrivate *priv = rp->priv;
        ...
        strcpy(priv->word1, w1);
        strcpy(priv->word2, w2);
    }
    ...
    

    Der Benutzer sieht nur RhymePair.h und weiß nicht, wie 'private' aufgebaut ist, muss also sich streng an die API halten.

    Das ist natürlich nicht 100% sicher, denn wenn ich RhymePrivate.c kenne, dann kann ich trotzdem auf die private Elemente zugreifen.



  • Die Redmonder haben es ungefähr so gemacht:

    typedef handle;
    

    Klappt übrigens nur in C, nicht in C++. Effektiv ist handle ein leerer Typ, und leere Typen sind per Default int. Intern ist es sicherlich ein struct Pointer, aber das lässt sich schwer nachprüfen. Das einzige was man da noch machen kann ist dereferenzieren und sich die binären Werte ansehen und irgendwie raten was dahinter stecken könnte.

    Es gibt eine noch fiesere Methode:

    //geheim
    static struct geheim *array[];
    static struct geheim *handleToGeheim(handle h){
        return array[h];
    }
    
    static handle geheimToHandle(struct *geheim){
        handle h = getFreeHandle(array);
        array[h] = geheim;
        return h;
    }
    
    //öffentlich
    typedef handle;
    void doSomething(handle h){
        struct geheim *g = handleToGeheim(h);
        //arbeite mit g
    }
    

    Hier ist handle nur irgendein int. Man kann es nichtmal dereferenzieren. Solange man die Adresse vom array oder von handleToGeheim nicht errät hat man keine Chance. Ich würde sagen sicherer wirds nicht. Aber wie gesagt, überlege dir genau ob du Programmierer so ärgern willst.


Anmelden zum Antworten