Compiler Error C2017 "illegal escape sequence"



  • Hi Community,

    Ich möchte auf dem Bildschirm folgenden Text ausgeben, welcher selbst Anführungszeichen enthält:

    +12V "ON"
    

    Die folgende Codezeile wird als fehlerhaft vom Compiler abgelehnt:

    VERIFY( SetDlgItemText( hwnd_dialog, IDC_RTS, TEXT( "+12V \"ON\"" ) ) );
    

    das gleiche passiert auch, wenn ich eine ganz normale CRT-Funktion verwende, z.B. (sinngemäß umgebaut)

    VERIFY( strcpy( csz_string, "+12V \"ON\"" ) != NULL );
    

    Das Makro VERIFY() ist eine #define-Anweisung welche hier z.B. in assert() umgewandelt wird.

    In beiden Fällen erhalte ich folgende Fehlermeldung:

    Compiler Error C2017 -> "illegal escape sequence" bzw. "Ungueltige ESCAPE-Folge"
    

    Beschreibung siehe: http://msdn.microsoft.com/en-us/library/29t70y03(VS.80).aspx

    Dort ist genau der zweite Beispiel beschrieben, was auf mein Problem zutrifft.

    Nun, nirgendwo steht geschrieben, wie ich das Problem lösen kann 😕

    Mein erster Gedanke war, den String in Einzelteilen zu zerlegen und mittels strcpy() bzw. strcat() in einer Variable wieder zusammenzubauen....
    Aber das kann doch nicht die elegante Lösung sein, oder?
    Vor allem, wenn ich mit mehrsprachigen Ressourcen-Texte arbeite, ist das eine Zumutung!

    Habt Ihr vielleicht andere Tipps für mich parat?
    Martin



  • Hi ,

    ich tippe darauf, dass es an der Defintion vom VERIFY-Makro liegt. Das solltest Du Dir mal ansehen.
    Ein entsprechender Hinweis (nicht auf VERIFY aber auf Probleme mit Makros) findet sich auch auf der MSDN-Seite, die Du verlinkt hast.

    und wieder mal: Makro sucks. 😉
    (Ich weiß: Kannst Du nichts für)

    Gruß,

    Simon2.



  • Hi Simon2,

    also, meine Makrodefinition für VERIFY() sieht wie folgt aus:

    //Die Funktion in VERIFY() wird sowohl in der Debug- als auch in der Release-Version aufgerufen,
    //  aber der Rückgabewert wird nur der Debug-Version auf korrekten (erwarteten) Wert != 0 hin überprüft.
    //  D.h. ein Rückgabewert gleich 0 (d.i. fehlerhafter Zustand) würde eine Assertion auslösen!
    #ifdef  _DEBUG
    #define VERIFY(x) (assert((x)!=0))
    #else
    #define VERIFY(x) ((void)(x))
    #endif // _DEBUG
    

    Ich denke, das sieht gar nicht verdächtig aus, oder doch?

    Simon2 schrieb:

    Ein entsprechender Hinweis (nicht auf VERIFY aber auf Probleme mit Makros) findet sich auch auf der MSDN-Seite, die Du verlinkt hast.

    Welcher Hinweis? Das mit dem Stringize Operator? Ich sehe nur daß diese dort aufgeführten Beispiele zur C2017 führen. Aber leider nicht wie man's lösen kann...
    Oder übersehe ich da was?

    Martin



  • Hi,

    ich würde an Deiner Stelle mal das Makro "per Hand ersetzen". Dann sieht man am ehesten, wo's kracht.
    BTW: könnte es sein, dass in Deiner Implementierung assert() selbst auch wieder ein Makro ist?

    Mmacher schrieb:

    ...
    Welcher Hinweis? Das mit dem Stringize Operator? Ich sehe nur daß diese dort aufgeführten Beispiele zur C2017 führen. Aber leider nicht wie man's lösen kann...
    Oder übersehe ich da was?

    Martin

    Nunja, es könnte sein, dass das eine Schwäche der konkreten Implementierung des VERIFY-Makros ist (auch, wenn ich sie derzeit noch nicht sehe). Dann kannst Du evtl.
    * entweder das Makro anpassen
    * oder den Aufruf geeignet modifizieren (da können sonst überflüssige Klammern Wunder wirken)
    * oder das Makro für Deinen Fall passend ersetzen.
    Sorry - so auf die Schnelle sehe ich da auch nichts...

    Gruß,

    Simon2.



  • Danke für Deine Tipps,
    ich werde mal an den Makros herumexperimentieren.



  • Simon2 schrieb:

    BTW: könnte es sein, dass in Deiner Implementierung assert() selbst auch wieder ein Makro ist?

    assert ist ein Makro, um zum Beispiel auch den übergebenen Ausdruck oder Zeilennummer/Datei auszugeben.

    17.4.1.2/5 schrieb:

    Names which are defined as macros in C shall be defined as macros in the C++ Standard Library, even if C
    grants license for implementation as functions. [Note: the names defined as macros in C include the following:
    assert, errno, offsetof, setjmp, va_arg, va_end, and va_start. —end note]

    Mmacher, eventuell unterstützt deine IDE einen Präprozessor-Output, dann kannst du selbst nachvollziehen, was nach dem Präprozessorlauf falsch ist. Bei MSVC++ kann man in den Projektoptionen bei der Kategorie "C++" zur Befehlszeile "/P" hinzufügen.



  • Nexus schrieb:

    ...ist ein Makro, um zum Beispiel auch den übergebenen Ausdruck oder Zeilennummer/Datei auszugeben....

    Ah! Vielen Dank! 😋 👍

    Gruß,

    Simon2.



  • Ja, assert() selbst ist wieder ein Makro, so wie Nexus beschrieben hat.

    Hab nun mal nach Vorschlag von Nexus die Option /P angewendet.
    Und was passiert?
    Die Fehlermeldung verschwindet... Doch warum eigentlich? 😕

    Aus der Original-Zeile in der Datei "ProcDlgSetupComPort_sub.cpp":

    VERIFY( SetDlgItemText( hwnd_dialog, IDC_TXD, TEXT( "+12V \"0\" \"SPACE\"" ) ) );
    

    Macht der Präprozessoer daraus die folgende Zeile (mit der Option /P aktiviert) in der Output-Datei "ProcDlgSetupComPort_sub.i":

    ((void)( ((SetDlgItemTextA( hwnd_dialog, 1041, "+12V \"0\" \"SPACE\"" ))!=0) || (_assert("(SetDlgItemTextA( hwnd_dialog, 1041, \"+12V \\\"0\\" \\\"SPACE\\"\" ))!=0", "c:\\projekte\\pccontrol\\procdlgsetupcomport_sub.cpp", 137), 0) ));
    

    (sorry, ich weiß, ist lang)

    Entferne ich die Option /P, so erhalte ich wieder die besagte Fehlermeldung.
    Dummerweise habe ich mit dieser Einstellung natürlich keine Präprozessor-Ausgabe mehr, um nachzusehen wo oder wie es kracht ....

    Mit /P habe ich zwar das Symptom unterdrückt, NUR: Was war die eigentliche Ursache für die Fehlermeldung???

    Allerdings tu ich ungern die Option /P belassen, da dadurch auch die Compilierzeit ins unerträgliche steigt 😮
    Z.B. aus einer 20kByte Quelltextdatei werden 3.5 MByte Präprozessor-Output, zumal ich ein großes Projekt habe (Anzahl der cpp-Dateien im dreistelligen Bereich).

    Martin



  • Mmacher schrieb:

    ...
    Die Fehlermeldung verschwindet... Doch warum eigentlich?..

    Ich denke, dass die Fehlermeldung vom Compiler kommt, der aber mit der Option /P gar nicht aktiv wird, sondern nur der Präprozessor.
    Deswegen "behebt" diese Option auch gar nicht Dein Problem, sondern hilft nur bei der Lösung: assert setzt den übergebenen Ausdruck selbst nochmal "in Gänsefüßchen" und ersetzt dabei die \" nicht richtig:

    _assert("(SetDlgItemTextA( hwnd_dialog, 1041, \"+12V \\\"0\\" \\\"SPACE\\"\" ))!=0"
    

    da steht zweimal \", wo \\" stehen sollte...
    (kann man bei genauer "Farbbeobachtung" auch sehen 😉 )

    Gruß,

    Simon2.



  • mal ne blöde Frage: wieso nimmst du für VERIFY ein Makro? Vorausgesetzt, dass assert wie üblich eh nur im Debugmodus etwas macht, sollte doch auch folgendes tun:

    template <class T>
    void VERIFY(T t)
    {
      assert(t != 0);
      (void)t; //Compilerwarnungen wegen unbenutzen Parametern im releasemodus vermeiden
    }
    


  • @pumuckl
    das Problem bei der Funktion ist einfach, dass du weniger Informationen über den Fehler bekommst. Das Macro weiß ja wo es ist (__LINE__, __FILE__, __func__) und es kennt den exakten Parameter (strcpy(...)). Bei einer Funktion bekommst du dann ja immer die Meldung, dass das assert "1 != 0" in der Funktion VERIFY Zeile x fehlgeschlagen ist. => nicht so hilfreich.



  • @Simon2:
    BINGO! Das ist die Ursache! 👍

    Eigentlich hätte ich da selber draufkommen müssen, daß der Stringaufbau nach der Makro-Expansion nicht mehr mit dem ursprünglichen String übereinstimmt.

    Dann werde ich mir das assert() Makro mal näher in Augenschein nehmen.
    Zur Not dieses ggf. durch ein modifiziertes ersetzen. Dazu werde ich wohl erst am Wochenende dazu kommen.

    Die hierbei gewonnenen Erkenntnisse schreibe ich natürlich auch hier hinein.

    @pumuckl:
    Dein Vorschlag ist so für mich unbrauchbar (rüdiger hat schon geantwortet)

    Martin



  • Wieso eigentlich auf Ungleichheit mit 0 prüfen? Das ist unnötig und verkompliziert nur den eigentlichen Assert-Ausdruck. Wenn du nicht gleich eine Zahl prüfst, finde ich das != 0 eher verwirrend.

    Ich meine, sowas spricht doch für sich:

    assert(IsEverythingOkay());
    

    Aber bei Folgendem ist zumindest mir nicht auf Anhieb klar, was gewollt ist, und ich frage mich, was die Ungleichung soll.

    assert(IsEverythingOkay() != 0);
    

    pumuckl, Makros können zwar hässlich sein, aber nicht immer haben Funktionen Vorteile. 😉



  • @nexus:
    Hmmmm, ja weißt Du, das ist bei uns jahrelange Praxisgewohnheit.

    Wir haben früher mit Assembler diverse Microcontroller aus Performance-Gründen möglichst einen Vergleich auf Null oder eben auf ungleich Null angestrebt.
    Bei der Umstellung auf Hochsprache wie C haben wir auch diese Gewohnheit (und wegen Algorithmus-Kompatibilität) beibehalten.
    Und irgendwie bleibt diese auch hier mit Visual C++ hartnäckig bestehen...
    Hast recht, notwendig ist das natürlich nicht.



  • Nun zum eigentlichen Problem:

    Im assert()-Makro ist ein Stringize-Operator # enthalten.
    Das habe ich bisher nicht gewußt.

    Dieser arbeitet offensichtlich nicht korrekt, wie man am expandierten Makro-Ausdruck des Präprozessors erkennen kann.
    Deshalb ist die Beschreibung nach MSDN http://msdn.microsoft.com/en-us/library/29t70y03.aspx korrekt und zu 100%ig auf das assert()-Makro anwendbar.

    Ein direkter Lösungsweg dieses Problems gibt es anscheinend nicht.
    Den Stringize-Operator # entfernen ist auch nicht sinnvoll, da dieser doch wesentlicher Bestandteil des assert()-Makros ist.

    In meinem Fall habe ich es anders gelöst:
    Statt direkt Texte (mit den Escape-Sequenzen) in der Funktion zu verwenden, verwende ich einen Pointer auf den String.
    Und die verschiedenen Strings habe ich in einem Array zusammengefaßt.
    Ist für zukünftige Übersetzungen in andere Fremdsprachen auch so pflegeleichter zu handhaben.

    Danke an allen die mir bei dem Problem geholfen hafen!
    Martin


Log in to reply