Macro- Malaisen mit Includes



  • Werte Forumsbesucher,

    ich bin gerade über eine Sache gestolpert, die mir komisch vorkommt.
    Wenn ich an und für sich identische Funktionen, aber unterschiedliche Hardwareports habe, ersetze ich den hardwarerelevanten Teil durch Macros, weil als Funktionsparameter zur Laufzeit Performanceprobleme auftreten.
    Das sieht so aus, daß ich per define alle Funktions- und Variablennamen ändere, den generischen Teil includiere, dann undefs setze, dann defines auf das neue Hardwareeck und nochmal den generischen Teil includiere.
    In Primitivfall sieht das so aus:

    // Generischer Teil gport.c
    
    void setport (unsigned char value);
    void clearport (unsigned char value);
    char getport (void);
    
    static char port;
    
    	void clearport (unsigned char value)
    {
    	port ~= value;
    } 
    
    void setport (unsigned char value)
    {
    	port = value;
    }
    
    char getport (void)
    {
    	return port;
    }
    
    // Alle Funktionen generieren
    // **********************
    // * Port 1
    // **********************
    #define clearport P1ClearPort
    #define setport P1SetPort
    #define port P1
    #define getport P1GetPort
    // -----------------------
    #include "gport.c"
    // -----------------------
    #undef port
    #undef clearport
    #undef setport
    #undef getport
    
    // **********************
    // * Port 2
    // **********************
    #define clearport P2ClearPort
    #define setport P2SetPort
    #define port P2
    #define getport P2GetPort
    // -----------------------
    #include "gport.c"
    // -----------------------
    #undef port
    #undef clearport
    #undef setport
    #undef getport
    

    Die Headerdatei:

    void P1SetPort(unsigned char value);
    void P1ClearPort(unsigned char value);
    
    void P2SetPort(unsigned char value);
    void P2ClearPort(unsigned char value);
    
    char P1GetPort(void);
    char P2GetPort(void);
    

    Und natürlich die Main:

    #include <stdio.h>
    #include "ports.h"
    int main(int argc, char *argv[])
    {
    	unsigned char p1v = 1 , p2v = 2;
    
    	P1SetPort(p1v);
    	P2SetPort(p2v);
    	printf("Port 1 is %d\n",P1GetPort());
    	printf("Port 2 is %d\n", P2GetPort());
        return 0;
    }
    

    Das funktioniert auch. Jetzt ist es nur so, daß ich in ports.c Zeile 7 und 22 auskommentieren kann, ohne daß sich der Compiler aufregt. Eigentlich müßte er bemerken, daß er jetzt zweimal einen static char namens port anlegt, ist ihm aber in diesem Fall völlig wurscht. Natürlich funktioniert es dann auch nicht mehr, weil beide male "port" beschrieben und ausgelesen wird (also wird zweimal "2" ausgegeben).
    In anderen Fällen bemerkt er das, ohne daß mir eine besondere Systematik auffallen würde, womit das zusammenhängen kann. 😕
    Peinlich wird's halt dadurch, daß mir solche Schlampereien immer erst beim Debuggen auffallen und es bei solchen Überlagerungsphänomenen oft recht kniffelig wird, konkurrierende Zugriffe als solche zu ertappen.

    Also habt ihr eine Ahnung, was mir da in die Suppe spuckt oder ein anderes, sichereres Schema, wie man so was macht? Meins kommt mir eh' etwas umständlich vor ...

    Danke für's Nachdenken! 😉



  • pointercrash() schrieb:

    ...oder ein anderes, sichereres Schema, wie man so was macht? Meins kommt mir eh' etwas umständlich vor ...

    das sieht, in der tat, verdammt umständlich aus. mach's z.b. so:

    int P1 = 0;  // <-- demo variable
    
    #define GETPORT(a) (a)
    #define SETPORT(a,b) ((a)=(b))
    #define CLRPORT(a,b) ((a)=(a)&~(b))  // <-- oder irgendwie anders
    
    int main()
    {
        printf ("%x\n", GETPORT(P1));
        SETPORT (P1, 0x81);
        printf ("%x\n", GETPORT(P1));
        CLRPORT (P1, 0x01);
        printf ("%x\n", GETPORT(P1));
    }
    

    ^^oder hab ich dich falsch verstanden?
    🙂



  • ;fricky schrieb:

    pointercrash() schrieb:

    ...oder ein anderes, sichereres Schema, wie man so was macht? Meins kommt mir eh' etwas umständlich vor ...

    das sieht, in der tat, verdammt umständlich aus. mach's z.b. so:
    ...
    ^^oder hab ich dich falsch verstanden?
    🙂

    Das haut wunderbar hin für so Einzeiler, aber nicht mehr, wenn Du ganze Automaten duplizieren, aber nur einmal warten magst.

    Eine Erklärung für das eigenartige Phänomen wär' mir eigentlich jetzt wichtiger, Denkanstöße für zukünftige Umbauten nehme ich natürlich trotzdem gerne mit. 😉



  • pointercrash() schrieb:

    Das haut wunderbar hin für so Einzeiler, aber nicht mehr, wenn Du ganze Automaten duplizieren, aber nur einmal warten magst.

    das verstehe ich nicht. was stört dich an SETPORT (P1, x) vs. P1SetPort(x) ? zumal du das ja auch mit makros hinbekommst:

    #define P1SetPort(x) SETPORT(P1,(x))
    

    zu deinem bug: du hast eine variable 'static char port', aber auch #defines für 'port', dass muss sich ja irgendwie beissen.
    🙂



  • ;fricky schrieb:

    pointercrash() schrieb:

    Das haut wunderbar hin für so Einzeiler, aber nicht mehr, wenn Du ganze Automaten duplizieren, aber nur einmal warten magst.

    das verstehe ich nicht. was stört dich an SETPORT (P1, x) vs. P1SetPort(x) ? zumal du das ja auch mit makros hinbekommst:

    #define P1SetPort(x) SETPORT(P1,(x))
    

    Naja, selbst wenn ich mit "function- like" replacements auskommen würde, müßte ich z.B. Statusvariable halten. Schwierig, weil Makros ja nur textuelle Ersetzungen darstellen. Versuch' mal einen Toggle- Automaten zu basteln, der von jedem Modul aufrufbar ist, das die entsprechende ".h" inkludiert.

    ;fricky schrieb:

    zu deinem bug: du hast eine variable 'static char port', aber auch #defines für 'port', dass muss sich ja irgendwie beissen.
    🙂

    Gar nicht! Es wird vor jedem Include der generischen Funktionen "port" durch "P1" bzw "P2" ausgetauscht. Rein textuell, funzt ja auch. Erst wenn ich die #defines für "port" wegnehme, geht das schief, dann wird immer "port" angesprochen, für den kein define existiert. Der Bug besteht darin, daß in einem Modul (#include hängt ja nur zusammen) zwei "static char port" existieren, die auf den gleichen Speicher verweisen und der Compiler nicht motzt.
    Bei anderen static chars in meinen so aufgebauten Modulen wird jedoch genörgelt.
    DAS ist es, was ich nicht verstehe. 😕



  • Ich tipp mal, dass das:

    static char port;
    static char port;
    

    eine Redeklaration ist. Wenn man das nicht will, könnte es helfen, da explizit Initialisierungen zu 0 reinzutun.



  • Bashar schrieb:

    Ich tipp mal, dass das:

    static char port;
    static char port;
    

    eine Redeklaration ist. Wenn man das nicht will, könnte es helfen, da explizit Initialisierungen zu 0 reinzutun.

    Hey, cool, das erklärt schonmal diese Sache so fast 👍
    Wenn ich das in EIN File setze, wird immer gemeckert, in include- Files versteckt nur bei Initialisierung bei Deklaration. Hast Du noch eine gesteigerte Ahnung, warum der Compiler das so handhabt?



  • Das würde mich sehr wundern, wenn das stimmt. Da hätte ich keine Erklärung für, im Gegenteil. Der Compiler kriegt ja von der Includiererei nichts mit.



  • Bashar schrieb:

    Das würde mich sehr wundern, wenn das stimmt. Da hätte ich keine Erklärung für, im Gegenteil. Der Compiler kriegt ja von der Includiererei nichts mit.

    Was meinst Du, was mich so wuschi macht? Eigentlich gibt's das ja nicht ...



  • Liebe Leute,
    weil's mir sonst einfach keiner glaubt, hab' ich den Präprozessor- Output abgefischt:
    ports.i, defines auskommentiert:

    // Zeile 14 ff
    void P1SetPort (unsigned char value);
    void P1ClearPort (unsigned char value);
    char P1GetPort (void);
    
    static char port;
    
    	void P1ClearPort (unsigned char value)
    {
    	port = value;
    }
    // ...
    // Zeile 52ff
    void P2SetPort (unsigned char value);
    void P2ClearPort (unsigned char value);
    char P2GetPort (void);
    
    static char port;
    
    	void P2ClearPort (unsigned char value)
    {
    	port = value;
    }
    

    und jetzt mit den defines:

    void P1SetPort (unsigned char value);
    void P1ClearPort (unsigned char value);
    char P1GetPort (void);
    
    static char P1;
    
    	void P1ClearPort (unsigned char value)
    {
     P1 = value;
    }
    
    void P1SetPort (unsigned char value)
    {
     P1 = value;
    }
    // ...
    // Zeile 52ff
    void P2SetPort (unsigned char value);
    void P2ClearPort (unsigned char value);
    char P2GetPort (void);
    
    static char P2;
    
    	void P2ClearPort (unsigned char value)
    {
     P2 = value;
    }
    

    Also steht in einer Datei zweimal "static char port" und keiner schimpft. 😮
    Immerhin hab' ich jetzt mittels Initialisierung eine Kontrolle, damit ich nichts vergesse. 🙂
    Falls jemandem was Schöneres einfällt, immer gerne her damit! 😉


Anmelden zum Antworten