C ++ printf con std :: string?

Según entiendo, esa string es un miembro del std nombres std , entonces, ¿por qué ocurre lo siguiente?

 #include  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; } 

enter image description here

Cada vez que se ejecuta el progtwig, myString imprime una cadena aparentemente aleatoria de 3 caracteres, como en el resultado anterior.

Está comstackndo porque printf no es seguro, ya que usa argumentos variables en el sentido C 1 . printf no tiene opción para std::string , solo una cadena 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 podría pasar cualquier cosa.

La forma más fácil de solucionar esto, ya que está usando C ++, es imprimirlo normalmente con std::cout , ya que std::string admite eso a través de la sobrecarga del operador:

 std::cout << "Follow this command: " << myString; 

Si, por algún motivo, necesita extraer la cadena de estilo C, puede usar el método c_str() de std::string para obtener un const char * que tenga terminación nula. Usando tu ejemplo:

 #include  #include  #include  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.c_str()); //note the use of c_str cin.get(); return 0; } 

Si desea una función que sea como printf , pero escriba safe, mire en plantillas variadic (C ++ 11, compatible con todos los comstackdores principales a partir de MSVC12). Puedes encontrar un ejemplo de uno aquí . No hay nada que yo sepa implementado de esa manera en la biblioteca estándar, pero puede haber en Boost, específicamente boost::format .


[1]: Esto significa que puede pasar cualquier cantidad de argumentos, pero la función depende de usted para contarle el número y los tipos de esos argumentos. En el caso de printf , eso significa una cadena con información de tipo codificado como %d significa int . Si miente sobre el tipo o número, la función no tiene una forma estándar de conocimiento, aunque algunos comstackdores tienen la capacidad de verificar y dar advertencias cuando miente.

No use printf("%s", your_string.c_str());

Use cout << your_string; en lugar. Corto, simple y tipo seguro. De hecho, cuando escribe C ++, generalmente quiere evitar printf completo: es un remanente de C que rara vez se necesita o es útil en C ++.

En cuanto a por qué debería usar cout lugar de printf , las razones son numerosas. Aquí hay una muestra de algunos de los más obvios:

  1. Como muestra la pregunta, printf no es seguro para tipos. Si el tipo que pasa difiere del especificado en el especificador de conversión, printf intentará usar lo que encuentre en la stack como si fuera el tipo especificado, dando un comportamiento indefinido. Algunos comstackdores pueden advertir sobre esto en algunas circunstancias, pero algunos comstackdores no pueden / no lo harán en absoluto, y ninguno puede hacerlo bajo ninguna circunstancia.
  2. printf no es extensible. Solo puedes pasarle tipos primitivos. El conjunto de especificadores de conversión que comprende está codificado en su implementación, y no hay forma de que agregue más / otros. La mayoría de los C ++ bien redactados deberían usar estos tipos principalmente para implementar tipos orientados hacia el problema que se está resolviendo.
  3. Hace que el formateo decente sea mucho más difícil. Para un ejemplo obvio, cuando está imprimiendo números para que las personas lean, normalmente desea insertar separadores de miles cada pocos dígitos. La cantidad exacta de dígitos y los caracteres utilizados como separadores varía, pero cout tiene eso cubierto. Por ejemplo:

     std::locale loc(""); std::cout.imbue(loc); std::cout << 123456.78; 

    La configuración regional sin nombre (el "") elige una configuración regional en función de la configuración del usuario. Por lo tanto, en mi máquina (configurada para inglés estadounidense) se imprime como 123,456.78 . Para alguien que tiene su computadora configurada para (digamos) Alemania, imprimiría algo así como 123.456,78 . Para alguien con la configuración para India, imprimiría como 1,23,456.78 (y, por supuesto, hay muchos otros). Con printf obtengo exactamente un resultado: 123456.78 . Es consistente, pero es sistemáticamente incorrecto para todos en todas partes. Básicamente, la única forma de evitarlo es hacer el formateo por separado, luego pasar el resultado como una cadena a printf , porque printf sí mismo simplemente no hará el trabajo correctamente.

  4. Aunque son bastante compactas, las cadenas de formato de printf pueden ser bastante ilegibles. Incluso entre los progtwigdores de C que usan printf prácticamente todos los días, supongo que al menos el 99% necesitaría buscar cosas para estar seguro de qué significa el # en %#x , y cómo eso difiere de lo que significa el # en %#f (y sí, significan cosas completamente diferentes).

utiliza myString.c_str () si quieres una cadena tipo c (const char *) para usar con printf

Utilice std :: printf y c_str () ejemplo:

 std::printf("Follow this command: %s", myString.c_str()); 

Printf es bastante bueno para usar si el tamaño importa. Es decir, si está ejecutando un progtwig donde la memoria es un problema, entonces printf es en realidad una solución muy buena y bajo evaluación. Cout esencialmente desplaza los bits para dejar espacio para la cadena, mientras que printf simplemente toma algún tipo de parámetro y lo imprime en la pantalla. Si tuviera que comstackr un progtwig hello world simple, printf podría comstackrlo en menos de 60,000 bits, en lugar de cout, tomaría más de 1 millón de bits para comstackr.

Para su situación, id sugiere usar cout simplemente porque es mucho más conveniente de usar. Aunque, yo diría que printf es algo bueno de saber.

La razón principal es, probablemente, que una cadena C ++ es una estructura que incluye un valor de longitud actual, no solo la dirección de una secuencia de caracteres terminados por un byte 0. Printf y sus familiares esperan encontrar tal secuencia, no una estructura, y por lo tanto se confunden con las cadenas de C ++.

Hablando por mi cuenta, creo que printf tiene un lugar que no puede ser llenado fácilmente por las características sintácticas de C ++, así como las estructuras de tablas en html tienen un lugar que no puede ser llenado fácilmente por los 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 usarla como un obstáculo para compensar el código mal diseñado.

Sería bastante agradable si el proyecto GNU añadiera la familia printf a sus extensiones g ++.

printf acepta una cantidad variable de argumentos. Esos solo pueden tener tipos de datos antiguos simples (POD). El código que pasa algo que no sea POD a printf solo comstack porque el comstackdor supone que tienes tu formato correcto. %s significa que el argumento respectivo se supone que es un puntero a un char . En su caso, es una std::string not const 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 el argumento std::string en const char* el puntero resultante apuntará a una región de memoria irrelevante en lugar de a 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 con formato , (especialmente si tiene la intención de tener relleno), puede ser peligroso si no ha activado las advertencias del comstackdor. Siempre habilite las advertencias porque estos errores pueden evitarse fácilmente. No hay ninguna razón para utilizar el torpe mecanismo de std::cout si la familia printf 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 propia implementación de printf personalizada, debe declararla con el mecanismo __attribute__ que permite al comstackdor verificar la cadena de formato con los parámetros proporcionados .