C ++ equivalente de sprintf?


82

Sé que std::coutes el equivalente en C ++ de printf.

¿Cuál es el equivalente de C ++ sprintf?

Respuestas:


66

std::ostringstream

Ejemplo:

#include <iostream>
#include <sstream> // for ostringstream
#include <string>

int main()
{
  std::string name = "nemo";
  int age = 1000;
  std::ostringstream out;  
  out << "name: " << name << ", age: " << age;
  std::cout << out.str() << '\n';
  return 0;
}

Salida:

name: nemo, age: 1000

3
No creo que sprintf escriba en stdout. Quitaría la declaración de inserción anterior.
Raffi Khatchadourian

78
¿En qué se parece esto siquiera remotamente sprintf (...)? No puede formatear los datos de forma arbitraria, debe confiar en que el tipo se conoce cuando lo introduce en la secuencia utilizando el <<operador.
Andon M. Coleman

Necesito estar de acuerdo con @ AndonM.Coleman sobre este. Esto no es realmente un reemplazo de Sprintf. Esto sería más así, pero esto es Qt.
lpapp

como dice @vinkris en su respuesta, iomanip logra formatear. En lugar de imprimir en stdoit, diría "result = out.str ()".
Dmitri

sprintf / snprintf permite formatear e imprimir en una matriz de caracteres asignada por el usuario, puede estar en la pila. En el caso de snprintf (), asegura que no haya desbordamiento. Aquí estamos asignando memoria varias veces y la persona que llama no tiene acceso directo a ella. Tiene que convertir a una cadena para obtener la salida. Un std :: ostream con un std :: streambuf personalizado, que toma el búfer del usuario sería una mejor combinación; por supuesto, la construcción / destrucción de ostream / streambuf agrega más ineficiencia.
MGH

34

Actualización, agosto de 2019:

Parece que C ++ 20 tendrá std::format. La implementación de referencia es {fmt} . Si está buscando una printf()alternativa ahora, este se convertirá en el nuevo enfoque "estándar" y vale la pena considerarlo.

Original:

Utilice Boost.Format . Tiene una printfsintaxis similar, seguridad de tipos, std::stringresultados y muchas otras cosas ingeniosas. No volverás.


14
... a menos que le preocupe el tamaño de su ejecutable ..: P
pradyunsg

¿Qué impacto tendría esto? La dependencia de Boost sería solo de encabezado, sin vinculación, ¿correcto?
Ken Williams

1
@KenWilliams Sí, Boost.Format es solo encabezado. Una simple prueba de "hola, mundo" en mi Mac aumenta de 10kB a 78kB. En un proyecto real, el tamaño adicional se amortizará en todas las unidades de compilación (proporcione las opciones de enlazador correctas) y la seguridad de tipos aporta otros beneficios.
enero de 2017

17

sprintf funciona bien en C ++.


4
Creo que el OP significaba STL en lugar de C ++.
Jean-Michaël Celerier

4
sprintf requiere que asignes el búfer de caracteres. Me gustaría algo como el método "agregar" de "std :: string" que me permite agregar datos formateados y encargarme de la asignación entre bastidores.
Victor Eijkhout

7

Puede utilizar el archivo de encabezado iomanip para formatear el flujo de salida. ¡Mira esto !


¿Por qué alguien rechazó esto? ¿No es iomanip la forma pura de C ++ de lograr formateo en transmisiones? Creo que el objetivo aquí es evitar almacenar datos en cadenas de estilo C, lo que se logra con iomanip.
Dmitri

7

Aquí hay una buena función para un sprintf en c ++. Las transmisiones pueden ponerse feas si las usa demasiado.

std::string string_format(const std::string &fmt, ...) {
    int size=100;
    std::string str;
    va_list ap;

    while (1) {
        str.resize(size);
        va_start(ap, fmt);
        int n = vsnprintf(&str[0], size, fmt.c_str(), ap);
        va_end(ap);
   
        if (n > -1 && n < size) {
            str.resize(n); // Make sure there are no trailing zero char
            return str;
        }
        if (n > -1)
            size = n + 1;
        else
            size *= 2;
    }
}

En C ++ 11 y posteriores, se garantiza que std :: string usará un almacenamiento contiguo que termine en '\0', por lo que es legal convertirlo en char *using &str[0].

Se ha señalado que no se supone que los argumentos variados sigan el paso por referencia, y c ++ es bueno para no copiar cadenas si no es necesario. En ese caso, esto lo arregla.

std::string string_format(std::string fmt, ...) {

¡Muy buena solución! Lo he adaptado aquí: stackoverflow.com/a/3742999/15161 para que se ajuste más a sprintf-usage.
slashmais

10
Sin embargo, ilegal: (char*) str.c_str()desecha const.
MSalters

También hay un problema de desbordamiento de búfer al acecho
Barney Szabolcs

@MSalters Correcto. Hay una forma legal de hacerlo en C ++ 11.
whitequark

@whitequark: Siéntase libre de agregar eso como respuesta. En Stack Overflow, las buenas preguntas permanecen abiertas para permitir nuevas respuestas.
MSalters

0

Utilice un hilo de cadena para lograr el mismo efecto. Además, puede incluir <cstdio>y seguir utilizando snprintf.


0

Dependiendo de lo que planeas exactamente sprintf(), std::to_string()puede ser útil y más idiomático que otras opciones:

void say(const std::string& message) {
 // ...
}

int main() {
  say(std::to_string(5));
  say("Which is to say " + std::to_string(5) + " words");
}

La principal ventaja de std::to_string(), en mi humilde opinión, es que se puede extender fácilmente para admitir tipos adicionales que sprintf()ni siquiera pueden soñar con encadenar, algo así como el Object.toString()método de Java .

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.