Entiendo que string
es un miembro del std
espacio de nombres, entonces, ¿por qué ocurre lo siguiente?
#include <iostream>
int main()
{
using namespace std;
string myString = "Press ENTER to quit program!";
cout << "Come up and C++ me some time." << endl;
printf("Follow this command: %s", myString);
cin.get();
return 0;
}
Cada vez que se ejecuta el programa, myString
imprime una cadena aparentemente aleatoria de 3 caracteres, como en el resultado anterior.
Respuestas:
Está compilando porque
printf
no es de tipo seguro, ya que utiliza argumentos variables en el sentido C 1 .printf
no tiene opción parastd::string
, solo una cadena de estilo C. Usar algo más en lugar de lo que espera definitivamente no le dará los resultados que desea. En realidad es un comportamiento indefinido, por lo que cualquier cosa podría suceder.La forma más fácil de solucionar esto, ya que está usando C ++, es imprimirlo normalmente
std::cout
, yastd::string
que lo soporta mediante la sobrecarga del operador:Si, por alguna razón, necesita extraer la cadena de estilo C, puede usar el
c_str()
método destd::string
para obtener unaconst char *
terminación nula. Usando tu ejemplo:Si desea una función similar
printf
, pero segura, busque plantillas variadas (C ++ 11, compatible con todos los compiladores principales a partir de MSVC12). Puedes encontrar un ejemplo de uno aquí . No sé nada implementado de esa manera en la biblioteca estándar, pero puede haber en Boost, específicamenteboost::format
.[1]: Esto significa que puede pasar cualquier número de argumentos, pero la función depende de usted para decirle el número y los tipos de esos argumentos. En el caso de
printf
, eso significa una cadena con información de tipo codificada como%d
significadoint
. Si miente sobre el tipo o número, la función no tiene una forma estándar de conocimiento, aunque algunos compiladores tienen la capacidad de verificar y dar advertencias cuando miente.fuente
Por favor no use
printf("%s", your_string.c_str());
Usar en su
cout << your_string;
lugar. Corto, simple y seguro. De hecho, cuando escribe C ++, generalmente desea evitarlo porprintf
completo: es un resto de C que rara vez se necesita o es útil en C ++.En cuanto a por qué debe usar en
cout
lugar deprintf
, las razones son numerosas. Aquí hay una muestra de algunos de los más obvios:printf
no es de tipo seguro. Si el tipo que pasa difiere del dado en el especificador de conversión,printf
intentará usar lo que encuentre en la pila como si fuera el tipo especificado, dando un comportamiento indefinido. Algunos compiladores pueden advertir sobre esto en algunas circunstancias, pero algunos compiladores no pueden / no lo harán en absoluto, y ninguno puede hacerlo en todas las circunstancias.printf
No es extensible. Solo puede pasarle tipos primitivos. El conjunto de especificadores de conversión que entiende está codificado en su implementación, y no hay forma de agregar más / otros. La mayoría de los C ++ bien escritos deberían usar estos tipos principalmente para implementar tipos orientados al problema que se está resolviendo.Hace que el formateo decente sea mucho más difícil. Para un ejemplo obvio, cuando imprime números para que la gente los lea, generalmente desea insertar miles de separadores cada pocos dígitos. El número exacto de dígitos y los caracteres utilizados como separadores varían, pero
cout
tiene eso cubierto. Por ejemplo:La configuración regional sin nombre (la "") selecciona una configuración regional basada en la configuración del usuario. Por lo tanto, en mi máquina (configurada para inglés de EE. UU.), Esto se imprime como
123,456.78
. Para alguien que tiene su computadora configurada para (digamos) Alemania, imprimiría algo así123.456,78
. Para alguien con él configurado para India, se imprimiría como1,23,456.78
(y, por supuesto, hay muchos otros). Conprintf
puedo obtener exactamente un resultado:123456.78
. Es consistente, pero es consistentemente incorrecto para todos en todas partes. Esencialmente, la única forma de evitarlo es formatear por separado, luego pasar el resultado como una cadena aprintf
, porqueprintf
simplemente no hará el trabajo correctamente.printf
cadenas de formato pueden ser bastante ilegibles. Incluso entre los programadores de C que usanprintf
prácticamente todos los días, supongo que al menos el 99% necesitaría buscar cosas para asegurarse de lo que significa#
in%#x
y cómo difiere de lo que significa#
in%#f
(y sí, significan cosas completamente diferentes )fuente
#include <string>
. VC ++ tiene algunas rarezas en sus encabezados que le permitirán definir una cadena, pero no enviarlacout
, sin incluir el<string>
encabezado.cout
es más lento, es porque has usadostd::endl
donde no deberías.úsalo
myString.c_str()
si quieres una cadena tipo c (const char*
) con printfGracias
fuente
Utilice el ejemplo std :: printf y c_str ():
fuente
La razón principal es probablemente que una cadena de C ++ es una estructura que incluye un valor de longitud actual, no solo la dirección de una secuencia de caracteres terminados en un byte 0. Printf y sus familiares esperan encontrar una secuencia de este tipo, no una estructura, y por lo tanto se confunden con las cadenas de C ++.
Hablando por mí mismo, creo que printf tiene un lugar que no se puede llenar fácilmente con características sintácticas de C ++, al igual que las estructuras de tabla en html tienen un lugar que no se puede llenar fácilmente con divs. Como Dykstra escribió más tarde sobre el goto, no tenía la intención de comenzar una religión y en realidad solo estaba argumentando en contra de usarlo como un error para compensar el código mal diseñado.
Sería bastante bueno si el proyecto GNU agregara la familia printf a sus extensiones de g ++.
fuente
Printf es realmente bastante bueno para usar si el tamaño importa. Lo que significa que si está ejecutando un programa donde la memoria es un problema, printf es en realidad una solución muy buena y bajo evaluación. Cout esencialmente cambia los bits para dejar espacio para la cadena, mientras que printf solo toma algún tipo de parámetros y lo imprime en la pantalla. Si compilara un programa simple de hello world, printf podría compilarlo en menos de 60, 000 bits en lugar de cout, tomaría más de 1 millón de bits para compilar.
Para su situación, sugeriría usar cout simplemente porque es mucho más conveniente de usar. Aunque, diría que printf es algo bueno para saber.
fuente
printf
acepta un número variable de argumentos. Esos solo pueden tener tipos de datos antiguos simples (POD). Código que pasa cualquier cosa que no sea POD aprintf
solo compila porque el compilador asume que tienes el formato correcto.%s
significa que se supone que el argumento respectivo es un puntero a achar
. En tu caso es unstd::string
noconst char*
.printf
no lo sabe porque el tipo de argumento se pierde y se supone que debe restaurarse desde el parámetro de formato. Al convertir esestd::string
argumento enconst char*
el puntero resultante, apuntará a alguna región irrelevante de memoria en lugar de la cadena C deseada. Por esa razón, su código imprime galimatías.Si bien
printf
es una excelente opción para imprimir texto formateado (especialmente si tiene la intención de tener relleno), puede ser peligroso si no ha habilitado las advertencias del compilador. Siempre active las advertencias porque entonces errores como este son fácilmente evitables. No hay razón para usar elstd::cout
mecanismo torpe si laprintf
familia puede hacer la misma tarea de una manera mucho más rápida y bonita. Solo asegúrate de haber habilitado todas las advertencias (-Wall -Wextra
) y estarás bien. En caso de que use su propiaprintf
implementación personalizada , debe declararla con el__attribute__
mecanismo que permite al compilador verificar la cadena de formato con los parámetros proporcionados .fuente