Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

ph4nt0m

Frischling

  • »ph4nt0m« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student

  • Private Nachricht senden

1

15.07.2008, 12:17

char zu TCHAR bzw. zu std::basic_string<TCHAR> konvert

Hallo,

ich habe vor, meine Programme Unicode-tauglich zu machen, sodass man im besten Fall durch ein einfaches #define/#undef UNICODE "umschalten" kann. Jedenfalls verwende ich dazu TCHAR, das TEXT-Makro, sowie Strings, die je nach Definition der UNICODE-Konstante durch std::string oder eben std::wstring ersetzt werden.

In meinen eigenen Funktionten funktioniert das natürlich gut, doch was mache ich mit Zeichenketten, die mir beispielsweise durch Direct3D immer als einfaches char-Array geliefert werden? Will ich solche an eine Funktion übergeben, die eben einen std::wstring erwartet, kommt dabei ohne weiteres anscheinend nur Blödsinn heraus. Doch ich kann ja auch nicht grundsätzlich nach wchar_t umwandeln, denn wenn man dann die UNICODE-Definition aufhebt, erwartet die Funktion ja plötzlich keinen std::wstring, sondern einen std::string und alles würde wieder nicht richtig funktionieren.

Wie würde eurer Meinung nach die "beste" Lösung dafür aussehen?

Gruß,
ph4nt0m

ThePhil

Frischling

Beiträge: 23

Beruf: Schüler

  • Private Nachricht senden

2

15.07.2008, 12:42

Hi!

In den FAQs steht folgendes dazu:

Zitat von »"David_pb"«

Zitat von »"Beneroth"«

öhm, alles ganz schön ABER...

hat C++ selber neben dem Dateityp auch ne Funktion zum transcodieren? Oder muss ich die selber schreiben?

:?: ;)


Es ist ein Datentyp. Was meinst du mit transcodieren? Das Umwandeln von wchar_t in char, und umgekehrt? Dann gibt es einige Funktionen.

Zum Beispiel (CRT => Microsoftspezifisch aber sicherer Equivalent zu wcsrtombs: wcsrtombs_s):

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
mbstate_t mbstate;
const wchar_t* str1 = L"Hallo Welt";
char buffer[255] = {0};

memset((void*)&mbstate, 0, sizeof(mbstate));
wcsrtombs(buffer, &str1, 255, &mbstate);

if ( errno > 0 )
    printf( "widechar to multibyte encoding failed" );
else
    printf( "encoding succeeded: %s\n", buffer );


Oder (WinAPI):

C-/C++-Quelltext

1
2
3
4
5
6
7
const wchar_t* str1 = L"Hallo Welt";
char buffer[255] = {0};

if ( !WideCharToMultiByte(CP_UTF8, 0, str1, -1, buffer, 255, 0, 0) )
    printf( "widechar to multibyte encoding failed" );
else
    printf( "encoding succeeded: %s\n", buffer );


Oder (C++ Standard Library):

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
const wchar_t* str1 = L"Hallo Welt";
char buffer[255] = {0};

#if defined(_MSC_VER) && _MSC_VER < 1000
    using std::use_facet;
    if ( _USE( std::cout.getloc(), std::ctype<wchar_t> ).narrow(str1, str1 + wcslen(str1), '?', buffer) == 0 )
#else
    if ( std::use_facet< std::ctype<wchar_t> >(std::cout.getloc()).narrow(str1, str1 + wcslen(str1), '?', buffer) == 0 )
#endif
        printf( "widechar to multibyte encoding failed" );
    else
        printf( "encoding succeeded: %s\n", buffer );

ph4nt0m

Frischling

  • »ph4nt0m« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student

  • Private Nachricht senden

3

15.07.2008, 12:58

Erstmal danke für deine Antwort. Wenn ich das richtig sehe, geht es bei diesem FAQ-Eintrag allerdings nur um die Konvertierung von wchar_t in char, in meinem Fall ist der Ausgangstyp jedoch char. Natürlich gibt es die Funktionen sicherlich auch alle für die umgekehrte Richtung (findet man ja leicht mit google), doch das ist ja gar nicht mein Hauptproblem.

Es ging um den generischen Typen TCHAR, der je nach definierter Konstante in char oder in wchar_t umgewandelt wird. Die vorliegenden char-Arrays müssten also - abhängig von der UNICODE-Konstante - entweder unverändert oder eben nach wchar_t konvertiert übergeben werden. Ich denke, if-Abfragen an jeder kleinen Stelle wären wohl kaum ganz optimal :o

Gruß,
ph4nt0m

4

15.07.2008, 13:19

Öhh einfach die Funktion schreiben, darein dann nen #ifdef ob jetzt umwandeln soll oder nicht?!
Devil Entertainment :: Your education is our inspiration
Der Spieleprogrammierer :: Community Magazin
Merlin - A Legend awakes :: You are a dedicated C++ (DirectX) programmer and you have ability to work in a team? Contact us!
Siedler II.5 RttR :: The old settlers-style is comming back!

Also known as (D)Evil

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

5

15.07.2008, 13:23

Alles immer umzuwandeln halte ich eigentlich eher für Suboptimal. Da das viel zu viel Zusatzaufwand bedeutet. Aber falls du an dieser Lösung festhalten willst könntest du etwas in der Art versuchen:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
#if _UNICODE
  #define Convert DeineCharToWCharFunktionalitaet
#else
  #define Convert
#endif

// ...

std::wstring str = Convert( Foobar() );
@D13_Dreinig

ph4nt0m

Frischling

  • »ph4nt0m« ist der Autor dieses Themas

Beiträge: 81

Beruf: Student

  • Private Nachricht senden

6

15.07.2008, 13:33

Zitat von »"David_pb"«

Alles immer umzuwandeln halte ich eigentlich eher für Suboptimal. Da das viel zu viel Zusatzaufwand bedeutet.

Wie genau würdest du denn vorgehen? Lässt du Unicode komplett weg und benutzt immer std::string oder mischst du das ganze etwa in deinem Code? Bei VC++ 2008 ist ja offenbar schon standardmäßig Unicode definiert und ich dachte mir, dass es für die Zukunft auch nicht falsch wäre, komplett auf Unicode zu bauen!? :? Wie machen das denn eigentlich professionelle, kommerzielle Spiele? Ich bin mir mittlerweile nicht so sicher, was nun aktuell und in naher Zukunft der Standard ist/sein wird...

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

7

15.07.2008, 13:53

In vielen Fällen wird es reichen, falls kein Unicodesupport angeboten wird, einfach den jeweiligen Stringtyp zu verwenden. Falls du den String doch mal weiterreichen willst musst du dieser wirklich konvertiert werden.
Allerdings sind das eher Spezialfälle und nicht mit einer allgemeinen Lösung abzudecken.
@D13_Dreinig

ThePhil

Frischling

Beiträge: 23

Beruf: Schüler

  • Private Nachricht senden

8

15.07.2008, 14:04

Mir wäre eine etwas aufwändiger Weg eingefallen.
Zumindest einmal aufwendig und dann super ;)

Ich hab auch kA ob das überhaupt funktioniert, was mir grade durch den Kopf fliegt.

Also mir würde eine String-Klasse vorschweben, bei der du "einfach" die Cast-Operatoren für LPCWSTR bzw LPCSTR überlädst. Bzw als Konstruktormöglichkeit angibst.

Dann müsste der Compiler dadurch von Unicode auf Multi-Byte casten können, oder?


Ich weiß, vielleich bisschen mehr Arbeit aber wenn man so eine Klasse mal hat, ist sie sicher nett ;);)

Anonymous

unregistriert

9

15.07.2008, 15:08

uni_cast:
https://www.spieleprogrammierer.de/phpBB2/viewtopic.php?t=4701&highlight=unicast

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

10

15.07.2008, 15:57

Oder so:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <locale>
#include <cassert>
#include <vector>

template< typename D, typename S >
inline std::basic_string< D > uni_cast( const S* const src, const std::locale& locale = std::locale() )
{
    return src;
}

template<> 
inline std::basic_string< char > uni_cast( const wchar_t* const src, const std::locale& locale )
{
    assert( src != NULL );

#if defined( _MCS_VER ) && _MSC_VER < 1000
    using namespace std; \
    const std::ctype< wchar_t >* ctype = &_USE( locale, ctype< wchar_t > )
#else
    const std::ctype< wchar_t >* ctype = &std::use_facet< std::ctype< wchar_t > >( locale );
#endif

    const std::basic_string< wchar_t >::size_type len =
        std::char_traits< wchar_t >::length( src );
    std::vector< char > tmp( len );
    ctype->narrow( src, src + len, '?', &tmp[ 0 ] );
    return std::basic_string< char >( &tmp[ 0 ], len );
}

template<>
inline std::basic_string< wchar_t > uni_cast( const char* const src, const std::locale& locale )
{
    assert( src != NULL );

#if defined( _MCS_VER ) && _MSC_VER < 1000
    using namespace std; \
    const std::ctype< wchar_t >* ctype = &_USE( locale, ctype< wchar_t > )
#else
    const std::ctype< wchar_t >* ctype = &std::use_facet< std::ctype< wchar_t > >( locale );
#endif

    const std::basic_string< char >::size_type len = 
        std::char_traits< char >::length( src );
    std::vector< wchar_t > tmp( len );
    ctype->widen( src, src + len, &tmp[ 0 ] );
    return std::basic_string< wchar_t >( &tmp[ 0 ], len );
}
@D13_Dreinig

Werbeanzeige