Portierung Codegear 2007 auf XE 8



  • Hallo zusammen,

    hat jemand Erfahrung mit der Portierung von Codegear RAD Studio 2007 Projekten auf das Embarcadero RAD Studio XE8? Das Problem, das ich gerade habe, ist Folgendes:
    In einer Studio Version ist der Standarddatentype für Strings von AnsiString auf UnicodeString geändert worden. In unseren Anwendungen benutzen wir den AnsiString, und jetzt habe ich überall Mehrdeutigkeiten für fast alle String-Funktionen.
    Gibt es eine vernünftige Möglichkeit, die Verwendung von UnicodeStrings ganz auszuschließen, damit ich nicht jede Stringfunktion vollständig qualifizieren muss?

    `

    [bcc32 Fehler]: E2015 Mehrdeutigkeit zwischen '_fastcall System::Sysutils::AnsiUpperCase(const System::UnicodeString) und '_fastcall System::Ansistrings::AnsiUpperCase(const System::AnsiStringT<0>)'

    `

    Etwas nervig ist das schon 😡



  • Ich habe damals als ich von CB5 auf Rad Studio 2009 umgestiegen bin, in allen Dateien den Typ String durch AnsiString ersetzt, ging schnell mit "Suchen und Ersetzen".

    Trotzdem war auch da noch anschließend meist etwas Nacharbeit von Hand angesagt. 😃 😃



  • Warum benutzt ihr nicht String statt AnsiString und wandelt nur dort nach AnsiString um, wo es unbedingt erforderlich ist?

    Kannst du außerdem mal die Codezeile posten (und ggf. die Typen dazuschreiben), damit ich verstehen kann, wo der Fehler herkommt? Ich weiß, daß es implizite Umwandlungen zwischen den Stringtypen gibt, und daß die RTL einige Überladungen für beide Stringtypen enthält, was in Delphi unbedenklich ist, weil die overload resolution ein bißchen anders funktioniert (und was insbesondere fast nie eine Fehlermeldung produziert, weil Delphi mit Mehrdeutigkeiten anders umgeht als C++: meist wird die zuletzt definierte Funktion aufgerufen, so daß das Umordnen von uses -Statements gefährlich sein kann). Aber wenn das Argument, mit dem du die Funktion aufrufst, ein AnsiString (= AnsiStringT<0> ) ist, sehe ich nicht, warum das mehrdeutig ist.

    Edit: dieser Satz kein Verb



  • Die Mehrdeutigkeiten entstehen dadurch, dass es jeweils für AnsiString und UnicodeString Überladungen für den jeweils anderen Typ gibt.

    AnsiString::AnsiString( const UnicodeString& other );
    UnicodeString::UnicodeString( const AnsiString& other );
    

    Die dazugehörigen Funktionen gibt es dann auch mehrmals, z.B. für AnsiString und UnicodeString ,

    AnsiString AnsiUpperCase( const AnsiString& S );
    UnicodeString AnsiUpperCase( const UnicodeString& S );
    

    Die Mehrdeutigkeiten entstehen dadurch, dass AnsiString und UnicodeString durch ihren jeweiligen Konstruktor implizit ineinander konvertierbar sind und der Compiler alleine nicht entscheiden kann, welche Überladung er jetzt benutzen soll.
    Lustigerweise liegen die jeweiligen AnsiUpperCase-Funktionen in eigenen namespaces (Sysutils für Unicode und Ansistrings für AnsiStrings). In guter alter Delphi Manier wird in den .hpp Dateien zwar der namespace deklariert, aber am Ende der Datei mit using namespace sofort komplett eingebunden und damit ad absurdum geführt.

    Edit:
    Konkrete Codezeile

    AnsiString Line = Ansistrings::AnsiUpperCase( getenv( "PROMPT" ) );
    

    Ohne die Qualifizierung meldet mit der Compiler die o.g. Fehlermeldung. Interessanterweise werden für die Quelldatei nur drei Header eingebunden (System.AnsiStrings.hpp, windows.h und Tlhelp32.h). Der Compiler darf von Sysutils::AnsiUpperCase Funktion eigentlich gar nichts wissen, da nirgends Sysetm.SysUtils.hpp inkludiert wird 😮



  • DocShoe schrieb:

    Die Mehrdeutigkeiten entstehen dadurch, dass es jeweils für AnsiString und UnicodeString Überladungen für den jeweils anderen Typ gibt.

    Ja, schon, aber das ist in der Praxis kein Problem, wenn du nur mit Strings hantierst, also mit ( Unicode ) String oder AnsiString . Erst wenn du einen impliziten Konstruktor einer deiner Stringklassen verwenden willst (s.u.), wirds mehrdeutig.

    DocShoe schrieb:

    Lustigerweise liegen die jeweiligen AnsiUpperCase-Funktionen in eigenen namespaces (Sysutils für Unicode und Ansistrings für AnsiStrings). In guter alter Delphi Manier wird in den .hpp Dateien zwar der namespace deklariert, aber am Ende der Datei mit using namespace sofort komplett eingebunden und damit ad absurdum geführt.

    Du weißt aber, daß du das abschalten kannst, entweder grundsätzlich oder selektiv? Schau mal in die Delphi-Headerdateien, da sollte ein #ifdef -Guard für das using namespace sein. Man muß damit nur vorsichtig sein, weil der vom Formdesigner generierte Code implizites Scoping verwendet (was in Delphi ein Feature ist, in C++ jedoch nutzlos). Und mit SysUtils könnte das etwas schwierig werden, weil das Unit relativ grundlegend ist (da lebt z.B. Exception ).

    DocShoe schrieb:

    AnsiString Line = Ansistrings::AnsiUpperCase( getenv( "PROMPT" ) );
    

    Aha. getenv() gibt meines Wissens const char* zurück, braucht also einen impliziten Konstruktor, so daß das in der Tat eine mehrdeutig ist. Die richtige Lösung wäre, die Funktion aus der Delphi-RTL zu nehmen und nicht so eine obskure POSIX-Funktion:

    String Line = GetEnvironmentVariable("PROMPT");
    

    DocShoe schrieb:

    Interessanterweise werden für die Quelldatei nur drei Header eingebunden (System.AnsiStrings.hpp, windows.h und Tlhelp32.h). Der Compiler darf von Sysutils::AnsiUpperCase Funktion eigentlich gar nichts wissen, da nirgends Sysetm.SysUtils.hpp inkludiert wird 😮

    Bist du sicher, daß System.SysUtils.hpp nicht von System.AnsiStrings.hpp eingebunden wird?

    Erlaube mir außerdem erneut meine Frage:

    audacia schrieb:

    Warum benutzt ihr nicht String statt AnsiString und wandelt nur dort nach AnsiString um, wo es unbedingt erforderlich ist?

    Klar, vielleicht ist es euch im Moment nicht wichtig, aber es sollte schon klar sein, daß AnsiString verlustbehaftet ist und man nach Möglichkeit immer ( Unicode ) String verwenden sollte.



  • audacia schrieb:

    Warum benutzt ihr nicht String statt AnsiString und wandelt nur dort nach AnsiString um, wo es unbedingt erforderlich ist?

    Weil´s erst ein Mal ein Riesenaufwand ist, jede AnsiString Variable durch UnicodeString bzw. String zu ersetzen. Außerdem gibt´s Funktionen, die davon ausgehen, dass der zu Gunde liegende Datentyp ein char ist, da muss dann noch genau hingeguckt werden, ob und wie man das dann durch wchar_t ersetzen kann.
    Langfristig werden wir das aber wohl machen müssen.



  • DocShoe schrieb:

    Langfristig werden wir das aber wohl machen müssen.

    Gut, dann besteht ja Einigkeit 🙂

    Persönlich bevorzuge ich den Portierungsansatz, bei dem pauschal und halbautomatisiert AnsiString durch String ersetzt und dann nachgearbeitet wird durch explizites Einfügen von AnsiString -Konvertierungen. Der Vorteil ist, daß das Programm schon weitgehend Unicode-fähig ist und man relativ einfach die Stellen findet, an denen noch Datenverlust möglich ist. Aber in der Tat ist der Aufwand deutlich größer, und wenn die Codebasis nicht gut durch Unit-Tests abgedeckt ist, ist es auch nicht ganz risikoarm. Der schnellste Weg, das Programm zum Kompilieren zu bringen, ist die Variante von Burkhi.



  • audacia schrieb:

    ... Der schnellste Weg, das Programm zum Kompilieren zu bringen, ist die Variante von Burkhi.

    Aber auch der "verlustreichste", sprich es wird dann kein Unicode unterstützt. 😃
    Ist jedoch in Anbetracht der Tatsache, das die alte CB5 Umgebung (bzw. beim doc Rad studio 2007) das auch nicht konnte, gut zu verschmerzen.


Log in to reply