C ++ equivalente de sprintf?

82

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

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

lital maatuk
fuente

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
Vijay Mathew
fuente
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.

Janm
fuente
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 ++.

Steve Rowe
fuente
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 !

vinkris
fuente
¿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, ...) {
Erik Aronesty
fuente
¡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.

privilegios reales
fuente
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 .

Guss
fuente