(Visual) C++ Präprozessor -> String Operationen



  • Hallo zusammen,

    Ich möchte in ein char Array bestimmte Compiler-Eigenschaften speichern.
    Also sowas in der Art:

    const char MeinArray[] = sizeof(int);

    Nur soll nicht der integer Wert gespeichert werden sondern der (Zahlen-)Wert als String... (also sowas wie itoa)
    Das Array soll schon am Anfang des Programmes existieren und nicht erst zur Laufzeit erzeugt werden (also kein sprintf()).

    Ist sowas möglich?

    Danke & Gruß,

    Mark



  • Edit: Schrott -.-
    Ich sollte erst den ganzen Post lesen bevor ich antworte.



  • Nein, das ist nicht möglich.



  • Hmmm also eine Zahl in einen String zu kriegen kann man ja mittels so einem Makro:

    #define STRING(x) #x
    

    Nur wird sizeof() nicht evaluiert, d.h. es steht wirklich "sizeof(int)" im char Array 😞



  • Nein. Weder mit Präprozessor noch mit Templates.

    Wenn du die Daten unbedingt als String haben willst (was ich gerade nicht so ganz nachvollziehen kann), dann schreib dir doch eine kleines Ba(sh|tch)skript, dass ein Programm der Art

    int main ()
    {
        std::cout << "sizeof(int) = " sizeof (int) << ' ' << etc.
    }
    

    kompiliert, ausführt und die Ausgabe in eine andere Datei schreibt, umgeben von Anführungszeichen.

    Diese Datei kannst du dann in deinem Progamm inkludieren und benutzen.



  • Die "einfache" Version mit Templates:

    template <bool S, class A, class B> struct sel;
    
    template <class A, class B> struct sel<true, A, B>
    {
    	typedef A type;
    };
    
    template <class A, class B> struct sel<false, A, B>
    {
    	typedef B type;
    };
    
    // --------------------------------------------------------------------------
    
    template <char A1, char A2 = 0, char A3 = 0, char A4 = 0, char A5 = 0, char A6 = 0> struct strx
    {
    	static char const value[7];
    };
    
    template <char A1, char A2, char A3, char A4, char A5, char A6> char const strx<A1, A2, A3, A4, A5, A6>::value[7] = {A1, A2, A3, A4, A5, A6, 0};
    
    // --------------------------------------------------------------------------
    
    struct errx {};
    
    // --------------------------------------------------------------------------
    
    template <unsigned N> struct foo_
    	:	sel<(N < 10), strx<N+'0'>,
    		typename sel<(N < 100), strx<(N/10)+'0', (N%10)+'0'>,
    		typename sel<(N < 1000), strx<(N/100)+'0', (N/10)%10+'0', (N%10)+'0'>,
    		typename sel<(N < 10000), strx<(N/1000)+'0', (N/100)%10+'0', (N/10)%10+'0', (N%10)+'0'>,
    		typename sel<(N < 100000), strx<(N/10000)+'0', (N/1000)%10+'0', (N/100)%10+'0', (N/10)%10+'0', (N%10)+'0'>,
    		typename sel<(N < 1000000), strx<(N/100000)+'0', (N/10000)%10+'0', (N/1000)%10+'0', (N/100)%10+'0', (N/10)%10+'0', (N%10)+'0'>, errx
    		>::type>::type>::type>::type>::type>::type
    {
    };
    
    struct bar
    {
    	char c[123];
    };
    
    int main() 
    {
    	printf("%s\n", foo_<sizeof(bar)>::value);
    }
    

    Wer grössere Zahlen braucht muss entsprechend mehr tippen.
    Was IMO nicht geht ist dem Array einen selbstgewählten Namen zu geben, aber man kann immernoch einen Zeiger auf das erste Element statisch anlegen. Der müsste dann auch initialisiert sein bevor irgendwelcher Code ausgeführt wird:

    // ...
    char const* g_blubber = foo_<sizeof(bar)>::value;
    

    Wenn man etwas mehr Aufwand treibt kann man auch ein Array erzeugen welches für eine N-Stellige Zahl genau N (nicht terminiert) oder N+1 (null-terminiert) chars gross ist, allerding war mir das nu wirklich zuviel Aufwand für schnell-mal-eben.

    Vermutlich geht das auch alles eleganter, ist als "proof of concept" zu verstehen. (Wenn führende Nullen oder Spaces nicht stören geht's noch viel einfacher.)



  • Hab ne andere templateisierte Version:

    template<unsigned int I>
    struct ToChars 
    {
      enum {N =  (I<10) ? 2 : ToChars<I/10>::N+1 }; //recursive
      static void fill(char* ptr)
      {
        if (I>=10) ToChars<I/10>::fill(ptr);
        ptr[N-2] = ('0'+I%10); //angenommen '0'+1 = '1' etc. (*)
        ptr[N-1] = 0;
      }
    };
    
    template<> //to end the recursion
    struct ToChars<0> {
      enum {N=2};
      static void fill(char* ptr) { ptr[0] = '0'; ptr[1] = 0; }
    };
    
    template <typename T>
    struct SizeOfString {
      operator (const char*)() const { return data; }
      SizeOfString() { ToChars<sizeof(T)>::fill(data); }
    private: 
      char data[ToChars<sizeof(T)>::N];
    };
    

    Die Main koennte dann so aussehen:

    static SizeOfString<int> SizeOfIntString;
    int main()
    {
    cout << (const char*)SizeOfIntString << endl;
    }
    

    Ich weiss dass der SizeOfString struct nicht optimal ist, die idee liegt aber eh im ToChars, um bereits zur compilezeit die laenge des noetigen char arrays zu kennen und dieses array auch fuellen zu koennen. Ich hab leider keine Moeglichkeiten gefunden, bereits zur Compilezeit Stringliterale zusammenzubauen, werd mich aber mit beschaeftigen...



  • der präprozessor ersetzt doch textuell, ich würde sagen, man könnte das schon machen, aber nur wenn man den Anführungszeichen auch ein #define gibt.

    so etwa:

    #define az "  //Anführungszeichen
    //[...]
    const char meinArray[] = az sizeof(int) az;
    

    ich habs aber nicht getestet, und es wäre ziemlich gepfuscht. Aber du könntest drauf hoffen, dass das der compiler herausoptimiert. Ich denke, das der schon in der Lage sein könnte das zu finden.



  • Krux schrieb:

    der präprozessor ersetzt doch textuell, ich würde sagen, man könnte das schon machen, aber nur wenn man den Anführungszeichen auch ein #define gibt.

    so etwa:

    #define az "  //Anführungszeichen
    //[...]
    const char meinArray[] = az sizeof(int) az;
    

    das funktioniert leider nicht, weil der präprozessor ausgewertet wird, bevor der Compiler überhaupt die richtige parsearbeit übernimmt. Der Präprozessor ist also der allererste schritt.(um es genauer auszudrücken: zu dem zeitpunkt haben sachen wie "sizeof" oder "int" noch keine bedeutung)



  • sprich: bei dir stünde dann im endeffekt:

    const char meinArray[] = " sizeof(int) ";
    

    Und das siezeof(int) würde nichtmehr ausgewertet.


Anmelden zum Antworten