In einem Programm habe ich diese unscheinbare Schleife für eine spezielle Analyse im Debug-Mode eingebaut.

for (POSITION pos= m_aBind.GetHeadPosition(); pos; )

 S_BIND& b= m_aBind.GetNext(pos);
 TRACE(__FUNCTION__ “  %-32s %2d\n“,
  CT2A(b.sName.GetString()),
  b.GetStatus());
}

Sieht auf den ersten Blick OK aus.
Auf den zweiten Blick wundert einen evtl. die Nutzung von CT2A. Warum nehme ich nicht einfach den Zeiger von GetString wie er ist? Es ist ja ein PCTSTR! Begründung:

  1. Das Projekt ist ein Unicode Projekt. 
  2. CT2A verwende ich hier, weil die TRACE Funktion in dieser Schreibweise nur MBCS Strings verwendet. D.h. %s erwartet einen Zeiger auf einen MBCS String.
  3. Die _T Schreibweise für die Ausgabemaske ist hier nicht geeignet, weil ich gerne den Funktionsnamen auch mit ausgegeben hätte. Und __FUNCTION__ ist nun mal eine normale String-Konstante, und kein wchar_t-String.
  4. T2A verwende ich nicht, weil dies in einer Schleife tödlich ist, weil der Stack immer weiter anwächst.

OK! Soweit dazu, warum der Code aussieht wie er aussieht.

❗ Nur… es kommt nur Schrott dabei heraus!
Die Ausgabe zeigt brav, den Text, den ich haben möchte, nur die Zahlenwerte stimmen in keiner Weise mit den Rückgabewerten von GetStatus überein! Warum? ❓

Was ist passiert? Der Debugger gibt schnell Auskunft:
CT2W erzeugt ein Objekt vom Typ CW2AEX!!! Dieses Objekt ist aber größer als ein PCSTR Zeiger. Dieses Objekt umfasst bei meinen Projekteinstellungen 4 Bytes für einen Zeiger plus einen char-Array der Größe 128. TRACE hätte aber gerne einen 4-Byte Zeiger auf dem Stack und danach für die Ausgabe einen Integer.
Ausgegeben, werden also die 4 ersten Bytes des Puffers von CW2AEX und nicht die gewünschten numerischen Werte für GetStatus!

Das ist übrigens die selbe Falle in die man tritt, wenn man CString direkt ohne CString::GetString in printf/TRACE und Konsorten verwendet. Nur hat man hier das Glück, dass ein CString exakt 4 Bytes groß ist und genau aus einem Zeiger auf einen PTSTR besteht.

Wie macht man es richtig?
Genau… man führt den entsprechenden cast ein. Der cast benutzt nun den cast-Operator der Klasse CW2AEX, und der liefert uns den Zeiger den wir wollten.

for (POSITION pos= m_aBind.GetHeadPosition(); pos; )
{
 S_BIND& b= m_aBind.GetNext(pos);
 TRACE(__FUNCTION__ “ %-32s %2d\n“,
  static_cast<PCSTR>(CT2A(b.sName.GetString())),
  b.GetStatus());
}

Amerkungen:

  • Ich brauche wahrscheinlich nicht zu erwähnen, dass ähnliche Probleme mit CA2W, CA2T etc. auch auftauchen können.
  • An den meisten Stellen an denen, wir diese Konvertierungen, wie z.B. CT2A verwenden wird auch direkt ein PCTSTR erwartet, oder eben ein Zeiger auf den entsprechend konvertieren String. Dadurch wird implizit der Konvertierungs-Operator der Klasse aufgerufen und damit funktioniert ales wie es soll.
  • Auch wenn das Projekt ein MBCS Projekt gewesen wäre, hätte es die selben Probleme verursacht. Denn in diesem Fall wird aus CT2A eine Objekt der Klasse CA2AEX. Im Gegensatz dazu würde T2A einfach zu ener Noop.