## kombiniert im Makro nur die Bezeichner



  • Hallo,

    ich habe eine Headerdatei, die ich in eine andere .cpp Datei einbinde.

    // Headerdatei
    
    #ifndef H_TEST
    #define H_TEST
    
    #define T1 "T"
    #define T2 "T2"
    #define T3 T1 ## T2
    
    #endif
    

    ich möchte String als Makro kombinieren. ich kann T1 wunderbar benutzen und in der .cpp Datei ausgeben und benutzen, sowie T2. Wenn ich das mit T3 versuche (ausgeben), dann kommt die Meldung:

    error C2065: 'T1T2': nichtdeklarierter Bezeichner

    Das hat der Compiler gut erkannt... gibts ja auch gar nicht... aber wieso setzt T3 nur die Bezeichner zusammen und erzeugt einen neuen Bezeichner? ich finde überall im Internet "##" als Kombinationsoperator für zwei Zeichenketten. Das soll angeblich funktionieren, und tut es auch angeblich in jedem der Tutorials, wo es verwendet wird auf ganz simple Art, nämlich so wie ich es auch probiere, wieso hier nicht?

    ich dachte das läge an der Headerkonstanten, kann es aber nicht, da ja T1 und T2 abgefragt werden können und die Werte auch stimmen.

    (Bin btw schon ne Stunde oder mehr dran) Google liefert auch nicht viel Zeug dazu. Wäre für jede Hilfe dankbar.

    Ich verwende VC++ 2010 Express. 😕



  • Dieser Präprozessor-Operator setzt Tokens zusammen und keine Stringliterale. Du brauchst hier auch keinen, denn diese werden nämlich auch so zusammengesetzt:

    // Headerdatei
    
    #ifndef H_TEST
    #define H_TEST
    
    #define T1 "T"
    #define T2 "T2"
    #define T3 T1 T2
    
    #endif
    


  • Padmad schrieb:

    [...] aber wieso setzt T3 nur die Bezeichner zusammen und erzeugt einen neuen Bezeichner?

    Weil der ## Operator genau das tut, er kombiniert zwei Token zu einem.

    Padmad schrieb:

    ich finde überall im Internet "##" als Kombinationsoperator für zwei Zeichenketten.

    Dann hast du entweder überall was falsch verstanden oder überall im Internet, wo du geschaut hast, nur Mist gefunden...

    Direkt aufeinanderfolgende Stringliterale werden in Translation Phase 6 schon einfach so automatisch verkettet:

    #include <iostream>
    
    int main()
    {
      std::cout << "hello " "world!";
    }
    

    ist gültiges C++ und tut genau was du denkst.

    Mach also

    #define T3 T1 T2
    

    und fertig 😉



  • Vielen dank für die Antworten.
    Tatsächlich steht dann auf den 2 Seiten, die ich gestern dazu gefunden habe nur Schrott.

    Das kombinieren funktioniert so, wie ihr es gesagt habt, hilft mir aber nicht ganz bei meinem Problem. Vielleicht hätt ich das gleich präzisieren sollen.

    Ich möchte quasi ein Stammverzeichnis mit Dateikonstanten kombinieren und dann einbinden.

    /*globals.h*/
    
    #ifndef H_FILE
    #define H_FILE
    
    #define DIR "C:\User\project"
    #define FILE "\file.h"
    
    #define DIRFILE DIR FILE
    
    #endif
    

    Dann möchte ich diese Konstante DIRFILE in beispielsweise der main.cpp einbinden.

    #include "globals.h"
    #include DIRFILE
    

    Einfach, damit ich später bei allen Pfaden (außer globals.h) schnell was ändern kann, sollte es erforderlich sein.

    Das funktioniert so aber nicht. Es kommt der Fehler:

    warning C4067: Unerwartete Token nach Präprozessordirektive - Zeilenvorschub erwartet.
    fatal error C1083: Datei (Include) kann nicht geöffnet werden: "C:\User\project": Permission denied

    Das Problem ist, dass die FILE konstante nicht rangehangen wird beim includen, (irgendwie nicht Teil von DIRFILE ist).
    Wenn ich testweise aber eine neue Konstante in der Headerdatei (globals.h) schreibe:

    #define TEST "C:\User\project\file.h"
    

    ...funktioniert es ja.

    Deswegen dachte ich ja bis gestern, dass der ##-Operator das ermöglicht, da das einfache zusammensetzen, was ich erstmalig natürlich schon probiert hatte, nicht funktionierte und eben genau diesen Fehler erbrachte.

    Sorry, hätte gleich mit dem ganzen Problem kommen sollen.



  • Zeig mal den Code wo das Problem auftritt, evtl. mal das DIR FILE in Klammern setzen, weil es ja nur textuell ersetzt wird und sich ansonsten unünstige Ausdrücke ergeben könnten: #define DIRFILE (DIR FILE)



  • Also wenn ich die Konstante TEST einbinde, funktioniert es, meine ich, was mir zeigt, dass das prinzipiell möglich ist mit Konstanten in Verbindung mit include zu arbeiten.

    übrigens ist es vielleicht für's Verständnis besser sich für den quellcode im Beitrag über mir, den ich verfasst habe, anstatt H_FILE -> H_GLOBALS zu denken.
    Das sollte ja eh nur zeigen, wo mein Problem liegt.



  • Mit Klammerung hatte ich das auch schon probiert.
    Da erhalte ich:

    error C2006: '#include': Dateinamen erwartet, aber '(' gefunden

    sowie

    fatal error C1083: Datei (Include) kann nicht geöffnet werden: "": No such file or directory

    Hier mal der ganze Code:

    /*wD_globals.h*/
    
    #ifndef H_WDGLOBALS
    #define H_WDGLOBALS
    
    #define G_TITLE					(L"TITLE")
    #define G_WNDCLASS1				(L"WindowClassSWFC_1")
    #define G_DIR					"E:\Users\USER\Documents\Visual Studio 2010\Projects\swfc_dev\swfc_dev"
    
    #define G_FILEWINPROC			"\wD_winproc.h"
    
    #define TEST					"E:\Users\USER\Documents\Visual Studio 2010\Projects\swfc_dev\swfc_dev\wD_winproc.h"
    
    #define T3 (G_DIR G_FILEWINPROC)
    
    #endif
    

    und die .cpp Datei

    #include <windows.h>
    #include "E:\Users\USER\Documents\Visual Studio 2010\Projects\swfc_dev\swfc_dev\wD_globals.h"
    #include T3
    

    Fehlermeldung:

    1>e:\users\USER\documents\visual studio 2010\projects\swfc_dev\swfc_dev\wdmain.cpp(3): error C2006: '#include': Dateinamen erwartet, aber '(' gefunden
    1>e:\users\USER\documents\visual studio 2010\projects\swfc_dev\swfc_dev\wdmain.cpp(3): fatal error C1083: Datei (Include) kann nicht geöffnet werden: "": No such file or directory
    


  • Sry, hatte nicht gechecked, dass du das in einer #include Direktive machen willst. Das ist dort leider etwas anderes, da Stringliteral Concatenation erst nach der Verarbeitung von #includes passiert. Ich fürchte, das ordentlich hinzubekommen, wird schwierig...

    Aber irgendwie hab ich sowieso das Gefühl, dass du da gerade etwas im Code hinzuhacken versuchst, das eigentlich Aufgabe des Buildsystems wäre. Du kannst deinem Compiler natürlich sagen, in welchen Verzeichnissen er bei einem #include nach passenden Dateien suchen soll. Bei Visual C++ gibt es da z.B. zum einen die Additional Include Directories und zum anderen die VC++ Directories...



  • Das würde erklären, warum das mit einer Konstante funktioniert hat, aber nicht mit Kombination aus zwei Konstanten. Eigentlich sehr schade. Aber dann kann ich zumindest die ganzen Dateipfade komplett in Konstanten packen. Das macht es wenigstens noch ein bisschen erträglicher.

    Problem ist einfach, dass es ja immer mal sein kann, dass sich die Dateinamen, oder die Pfade ändern und auch, wenn ich es vielleicht in den Projekteinstellungen einstellen kann, ändert es ja nicht die Tatsache (weil eine headerdatei kann ja in einem Projekt mehrmals eingebunden werden), dass in jeder Datei dann der ungülltige Pfad wie:

    include "C:\Bla\Datei"
    

    steht. ich müsste es also in jeder Datei von Hand ändern, wo die Datei eingebunden wird. Sprich den neuen Pfad auch hinschreiben. So oder so, im Falle, wenn sich mal was verändert.

    Aber danke für die Hilfe. Dennoch was gelernt über Präprozessoren Direktiven 😛



  • Dass ich natürlich dann nur den Dateinamen angeben muss, ist mir übrigens klar, aber das Problem bleibt ja auch beim Dateinamen das Selbe 😃

    Padmad



  • Dein eigentliches Problem ist viel grundlegender, nämlich, dass du überhaupt erst absolute Pfade in den Quellcode schreiben willst. Du kannst dir gar nicht vorstellen, was für eine schlechte Idee das ist. Im Prinzip machst du deinen Computer in seiner momentanen Konfiguration, zum einzigen Zeitpunkt und Ort, an dem dein Code in der Geschichte des ganzen Universums jemals kompilieren wird. Mach deine Quellen niemals abhängig von absoluten Pfaden. Sowas zu managen ist Aufgabe des Buildsystems, genau dafür gibt es Dinge wie die VC++ Directories und Additional Include Directories Einstellungen des Compilers. Schau dir an, was die machen und verwend relative Pfade.



  • Ne, ich glaube wir reden aneinander vorbei.
    Es ging in diesem Beispiel zwar um den absoluten Pfad:

    C:\...usw
    

    Aber es ging eigentlich darum mit DIR einfach bestimmte Ordner festzulegen, die das Projekt besser Ordnen sollen und FILE sollte den Dateinamen bilden. Das sollte nie das Stammverzeichnis ersetzen, was ich ja mit dem Programm schon festgelegt habe. Das war nur ein schlecht gewähltes Beispiel wegen dem Verständnis des ## Operators.
    Was ich wirklich eigentlich vor hatte, war Beispielsweise das:

    DIR1 ".\Ordner1\"
    DIR2 ".\Ordner2\"
    
    FILE1 "header.h"
    
    DIR1FILE1 DIR1 FILE1
    

    Das ist bei mir jetzt quasi aber nur noch eine Konstante, was ja okay ist, da zwei ordner bei mir wohl nicht die selbe Datei enthalten werden.


Log in to reply