Präprozessordefinition in Verkettungsoperator (##)



  • Ich habe eine Reihe von kompilierten Objektdateien, aus denen ich mir zur Laufzeit Funktionssymbole herauslade. Alle Objektdateien (hier "Module" genannt) müssen bestimmte Funktionen nach einem bestimmten Muster exportieren. Damit spätere Programmierer keine Probleme bei der Implementierung neuer Module haben, habe ich an einen Header gedacht (mod.h), welcher Präprozessormakros definieren soll, welche als Argument den Namen des Moduls annehmen und daraus einen einmaligen Namen bauen.

    Im Header sieht das so aus:

    #define MOD_DEFINE_STRING_RESOLVE    __ ## resolve
    #define MOD_DEFINE_STRING_INTERPRET  __ ## interpret
    
    #define MOD_DEFINE_RESOLVE(module_name)    module_name ## MOD_DEFINE_STRING_RESOLVE
    #define MOD_DEFINE_INTERPRET(module_name)  module_name ## MOD_DEFINE_STRING_INTERPRET
    

    In den Sources der Module wäre das dann:

    #define MODULE_NAME xyz
    
    #include <mod.h>
    
    int MOD_DEFINE_RESOLVE(MODULE_NAME)(void)
    {
            return 1;
    }
    
    int MOD_DEFINE_INTERPRET(MODULE_NAME)(void)
    {
            return 1;
    }
    

    Der Grund, warum MOD_DEFINE_STRING_RESOLVE und Konsorten separat definiert werden, ist weil das Programm, welches die Module einlädt, Mustererkennung machen muss, und ich da ebenfalls die Konstanten definiert haben will.

    Das Problem: der Verkettungsoperator interpretiert MOD_DEFINE_STRING_xyz nicht als über #define definiertes Symbol (wahrscheinlich aus einem guten Grund), sondern als Konstante. Sprich, statt:

    int xyz__resolve(void)
    

    wird stattdessen das Symbol:

    int xyz__MOD_DEFINE_STRING_RESOLVE(void)
    

    generiert.

    Meine Frage wäre, wie man, ohne dass man zusätzliche Parameter in das Makro einbringt, den Präprozessor dennoch dazu bringen könnte, die Symbole als Makros zu behandeln - schließlich sind diese auch schon zur Kompilierzeit bekannt. Kompiliert mit dem GCC 4.7.3.

    Vielen Dank im Voraus für mögliche Lösungsansätze.


  • Mod

    #define CONCAT_IMPL(A,B) A ## B
    #define CONCAT(A,B) CONCAT_IMPL(A,B)
    
    #define MOD_DEFINE_RESOLVE(module_name)  CONCAT(module_name, MOD_DEFINE_STRING_RESOLVE)
    #define MOD_DEFINE_INTERPRET(module_name)  CONCAT(module_name, MOD_DEFINE_STRING_INTERPRET)
    

    Übrigens kannst du statt

    #define MOD_DEFINE_STRING_RESOLVE    __ ## resolve
    

    Auch

    #define MOD_DEFINE_STRING_RESOLVE    __resolve
    

    schreiben, außer __ oder resolve wären selber Makros.



  • #define CONCAT_IMPL(A,B) A ## B
    #define CONCAT(A,B) CONCAT_IMPL(A,B)
    
    #define MOD_DEFINE_RESOLVE(module_name)  CONCAT(module_name, MOD_DEFINE_STRING_RESOLVE)
    #define MOD_DEFINE_INTERPRET(module_name)  CONCAT(module_name, MOD_DEFINE_STRING_INTERPRET)
    

    Alleine dadurch, dass das Symbol in der Parameterliste des Makro definiert wird, findet bereits die Ersetzung statt? Manchmal ergibt der Präprozessor keinen Sinn, zumindest nicht für mich ,,,

    Egal. Es funktioniert hervorragend. Vielen Dank für die Hilfe!


  • Mod

    Präprozessor schrieb:

    Alleine dadurch, dass das Symbol in der Parameterliste des Makro definiert wird, findet bereits die Ersetzung statt? Manchmal ergibt der Präprozessor keinen Sinn, zumindest nicht für mich ,,,

    Das ist auch nicht der Trick. Die hier relevante Regel ist, dass ein Makroargument nicht expandiert wird, wenn es als Argument von # oder ## benutzt wird, bevor # bzw. ## selber stattfinden. In meinem Code wird dieses Verhalten durch die Indirektion verhindert, denn normalerweise werden Makroargumente vor ihrer Nutzung vollständig ausgewertet. Also in CONCAT werden alle Argumente expandiert und dann in CONCAT_IMPL zusammengefügt.


Anmelden zum Antworten