2011-07-07 6 views
11
class MyString 
{ 
public: 
    MyString(const std::wstring& s2) 
    { 
     s = s2; 
    } 

    operator LPCWSTR() const 
    { 
     return s.c_str(); 
    } 
private: 
    std::wstring s; 
}; 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    MyString s = L"MyString"; 
    CStringW cstring = L"CString"; 
    wprintf(L"%s\n", (LPCWSTR)cstring); // Okay. Becase it has an operator LPCWSTR() 
    wprintf(L"%s\n", cstring); // Okay, fine. But how?   
    wprintf(L"%s\n", (LPCWSTR)s); // Okay. fine. 
    wprintf(L"%s\n", s); // Doesn't work. Why? It prints gabage string like "?." 
    return 0; 
} 

¿Cómo se puede pasar CString para formatear la cadena% s?¿Cómo se puede pasar CString para formatear la cadena% s?

Por cierto, MSDN says (que es raro)

utilizar un objeto CString en una función de argumentos variable
explícitamente el CString a una cadena LPCTSTR, como se muestra aquí:

CString kindOfFruit = "bananas"; 
int  howmany = 25; 
printf("You have %d %s\n", howmany, (LPCTSTR)kindOfFruit); 
+2

¿Qué significa "no funciona"? No compila, no muestra el resultado esperado ...? – MikMik

+2

Esto no tiene absolutamente nada que ver con C. – Puppy

+0

@MikMik: muestra una cadena de caracteres como ** "?." ** – Benjamin

Respuesta

9

CString está específicamente diseñado de modo que solo contiene un puntero que apunta a los datos de cadena en una clase de memoria intermedia. Cuando se pasa por valor a printf, se tratará como un puntero al ver el "% s" en la cadena de formato.

Originalmente, casualmente funcionó con printf por casualidad, pero luego se mantuvo como parte de la interfaz de clase.


Este post está basado en documentación de MS desde hace mucho tiempo retirado, así que no puedo vincular a su promesa de que van a seguir para hacer este trabajo.

Sin embargo, antes de añadir más downvotes también, por favor leer esta entrada del blog de alguien compartir mi conocimiento antiguo:

Big Brother helps you

+2

Todavía no sé cómo imprimirlo usando 'printf'. ¿Podrías mostrar un ejemplo? –

6
wprintf(L"%s\n", (LPCWSTR)cstring); // Okay. It's been cast to a const wchar_t*. 
    wprintf(L"%s\n", cstring); // UNDEFINED BEHAVIOUR 
    wprintf(L"%s\n", (LPCWSTR)s); // Okay, it's a const wchar_t*. 
    wprintf(L"%s\n", s); // UNDEFINED BEHAVIOUR 

lo solamente se puede pasar a esta func ción para %s es un const wchar_t*. Cualquier otra cosa es un comportamiento indefinido. Pasar el CString simplemente funciona.

Hay una razón por la que iostream se desarrolló en C++, y es porque estas funciones de argumento variable son horriblemente inseguras y nunca se deben usar. Ah, y CString es un pecado también por muchas razones, se adhieren a std::wstring y cout/wcout siempre que sea posible.

+3

El comportamiento indefinido de CString es en realidad un comportamiento específico de implementación. Microsoft admite este uso. –

+2

@BoP es un comportamiento indefinido en C++, porque es un comportamiento indefinido en la documentación estándar 'printf' de la biblioteca de C. Eso microsoft le da un significado (todavía tengo que ver una documentación oficial que sí lo hace) está bien, pero el código aún no es portátil. –

+1

@Johannes - Seguro que sí, pero la pregunta era por qué funciona de todos modos para CString. –

2

En términos generales es un comportamiento indefinido. De acuerdo con this article, Visual C++ solo invoca la conversión de CString a un tipo de POD para cubrirlo: esa es la implementación permisible del comportamiento indefinido.

3

CString tiene un puntero como el primer miembro:

class CStringA 
{ 
     char* m_pString; 
}; 

Aunque no es char* (incluso para ANSI CString), que es más o menos lo mismo. Cuando pasa el objeto CString a cualquiera de las funciones de la familia printf (incluida su implementación personalizada, si corresponde), está pasando el objeto CString (que está en la pila). El análisis %s hace que se lea como si fuera un puntero, que es un puntero válido en este caso (los datos en el primer byte son m_pString).

Cuestiones relacionadas