'printf' frente a 'cout' en C ++

Cuál es la diferencia entre printf() y cout en C ++?

preguntado el 20 de mayo de 10 a las 06:05

16 Respuestas

Me sorprende que todos en esta pregunta afirmen que std::cout es mucho mejor que printf, incluso si la pregunta solo pedía diferencias. Ahora, hay una diferencia: std::cout es C ++, y printf es C (sin embargo, puede usarlo en C ++, al igual que casi cualquier otra cosa de C). Ahora, seré honesto aquí; ambas cosas printf y std::cout tienen sus ventajas.

Diferencias reales

Extensibilidad

std::cout es extensible. Sé que la gente dirá eso printf también es extensible, pero dicha extensión no se menciona en el estándar C (por lo que tendría que usar características no estándar, pero ni siquiera existe una característica común no estándar), y tales extensiones son una letra (por lo que es fácil entrar en conflicto con un formato ya existente).

Diferente a la printf, std::cout depende completamente de la sobrecarga del operador, por lo que no hay problema con los formatos personalizados; todo lo que hace es definir una std::ostream como primer argumento y su tipo como segundo. Como tal, no hay problemas de espacio de nombres; siempre que tenga una clase (que no se limite a un carácter), puede tener funcionando std::ostream sobrecarga por ello.

Sin embargo, dudo que mucha gente quiera ampliar ostream (para ser honesto, rara vez vi tales extensiones, incluso si son fáciles de hacer). Sin embargo, está aquí si lo necesita.

Sintaxis

Como se pudo notar fácilmente, tanto printf y std::cout utilizar una sintaxis diferente. printf usa la sintaxis de función estándar usando cadenas de patrones y listas de argumentos de longitud variable. De hecho, printf es una razón por la que C los tiene - printf Los formatos son demasiado complejos para poder utilizarlos sin ellos. Sin embargo, std::cout utiliza una API diferente: la operator << API que se devuelve a sí misma.

Generalmente, eso significa que la versión C será más corta, pero en la mayoría de los casos no importará. La diferencia se nota cuando imprime muchos argumentos. Si tienes que escribir algo como Error 2: File not found., asumiendo el número de error, y su descripción es un marcador de posición, el código se vería así. Ambos ejemplos trabajar de manera idéntica (Especie de, std::endl en realidad vacía el búfer).

printf("Error %d: %s.\n", id, errors[id]);
std::cout << "Error " << id << ": " << errors[id] << "." << std::endl;

Si bien esto no parece demasiado loco (solo es dos veces más largo), las cosas se vuelven más locas cuando realmente formatea los argumentos, en lugar de simplemente imprimirlos. Por ejemplo, imprimir algo como 0x0424 es simplemente una locura. Esto es causado por std::cout estado de mezcla y valores reales. Nunca vi un idioma donde algo como std::setfill sería un tipo (distinto de C ++, por supuesto). printf separa claramente los argumentos y el tipo real. Realmente preferiría mantener el printf versión de la misma (incluso si parece un poco críptica) en comparación con iostream versión del mismo (ya que contiene demasiado ruido).

printf("0x%04x\n", 0x424);
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(4) << 0x424 << std::endl;

Traducción

Aquí es donde la verdadera ventaja de printf mentiras. La printf la cadena de formato está bien ... una cadena. Eso hace que sea realmente fácil de traducir, en comparación con operator << abuso de iostream. Suponiendo que el gettext() la función se traduce y quieres mostrar Error 2: File not found., el código para obtener la traducción de la cadena de formato mostrada anteriormente se vería así:

printf(gettext("Error %d: %s.\n"), id, errors[id]);

Ahora, supongamos que traducimos a Fictionish, donde el número de error está después de la descripción. La cadena traducida se vería así %2$s oru %1$d.\n. Ahora, ¿cómo hacerlo en C ++? Bueno, no tengo ni idea. Supongo que puedes fingir iostream que construye printf que puedes pasar a gettext, o algo así, con fines de traducción. Por supuesto, $ no es el estándar C, pero es tan común que, en mi opinión, es seguro de usar.

No tener que recordar / buscar una sintaxis de tipo entero específico

C tiene muchos tipos de enteros, al igual que C ++. std::cout maneja todos los tipos por ti, mientras printf requiere una sintaxis específica dependiendo de un tipo de entero (hay tipos que no son enteros, pero el único tipo no entero que usará en la práctica con printf is const char * (Cadena C, se puede obtener usando to_c método de std::string)). Por ejemplo, para imprimir size_t, necesitas usar %zd, mientras int64_t requerirá el uso %"PRId64". Las tablas están disponibles en http://en.cppreference.com/w/cpp/io/c/fprintf y http://en.cppreference.com/w/cpp/types/integer.

No puede imprimir el byte NUL, \0

Porque printf usa cadenas C en lugar de cadenas C ++, no puede imprimir el byte NUL sin trucos específicos. En ciertos casos es posible utilizar %c con '\0' como argumento, aunque claramente es un truco.

Diferencias que a nadie le importan

Rendimiento

Actualización: resulta que iostream es tan lento que normalmente es más lento que su disco duro (si redirige su programa a un archivo). Deshabilitar la sincronización con stdio puede ayudar si necesita generar una gran cantidad de datos. Si el rendimiento es una preocupación real (en lugar de escribir varias líneas en STDOUT), simplemente use printf.

Todo el mundo piensa que le importa el rendimiento, pero nadie se molesta en medirlo. Mi respuesta es que la E / S es un cuello de botella de todos modos, no importa si usa printf or iostream. pienso que printf podría ser más rápido de un vistazo rápido al ensamblaje (compilado con clang usando el -O3 opción del compilador). Asumiendo mi ejemplo de error, printf El ejemplo hace muchas menos llamadas que el cout ejemplo. Esto es int main con printf:

main:                                   @ @main
@ BB#0:
        push    {lr}
        ldr     r0, .LCPI0_0
        ldr     r2, .LCPI0_1
        mov     r1, #2
        bl      printf
        mov     r0, #0
        pop     {lr}
        mov     pc, lr
        .align  2
@ BB#1:

Puede notar fácilmente que dos cadenas y 2 (número) se empujan como printf argumentos. Eso es todo; no hay nada más. A modo de comparación, esto es iostream compilado para ensamblar. No, no hay alineación; cada uno operator << llamada significa otra llamada con otro conjunto de argumentos.

main:                                   @ @main
@ BB#0:
        push    {r4, r5, lr}
        ldr     r4, .LCPI0_0
        ldr     r1, .LCPI0_1
        mov     r2, #6
        mov     r3, #0
        mov     r0, r4
        bl      _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        mov     r0, r4
        mov     r1, #2
        bl      _ZNSolsEi
        ldr     r1, .LCPI0_2
        mov     r2, #2
        mov     r3, #0
        mov     r4, r0
        bl      _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        ldr     r1, .LCPI0_3
        mov     r0, r4
        mov     r2, #14
        mov     r3, #0
        bl      _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        ldr     r1, .LCPI0_4
        mov     r0, r4
        mov     r2, #1
        mov     r3, #0
        bl      _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
        ldr     r0, [r4]
        sub     r0, r0, #24
        ldr     r0, [r0]
        add     r0, r0, r4
        ldr     r5, [r0, #240]
        cmp     r5, #0
        beq     .LBB0_5
@ BB#1:                                 @ %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit
        ldrb    r0, [r5, #28]
        cmp     r0, #0
        beq     .LBB0_3
@ BB#2:
        ldrb    r0, [r5, #39]
        b       .LBB0_4
.LBB0_3:
        mov     r0, r5
        bl      _ZNKSt5ctypeIcE13_M_widen_initEv
        ldr     r0, [r5]
        mov     r1, #10
        ldr     r2, [r0, #24]
        mov     r0, r5
        mov     lr, pc
        mov     pc, r2
.LBB0_4:                                @ %_ZNKSt5ctypeIcE5widenEc.exit
        lsl     r0, r0, #24
        asr     r1, r0, #24
        mov     r0, r4
        bl      _ZNSo3putEc
        bl      _ZNSo5flushEv
        mov     r0, #0
        pop     {r4, r5, lr}
        mov     pc, lr
.LBB0_5:
        bl      _ZSt16__throw_bad_castv
        .align  2
@ BB#6:

Sin embargo, para ser honesto, esto no significa nada, ya que la E / S es el cuello de botella de todos modos. Solo quería mostrar eso iostream no es más rápido porque es "seguro para escribir". La mayoría de las implementaciones de C implementan printf formatos usando goto calculado, por lo que el printf es tan rápido como puede ser, incluso sin que el compilador sea consciente de printf (no es que no lo sean, algunos compiladores pueden optimizar printf en ciertos casos - cadena constante que termina con \n generalmente está optimizado para puts).

Herencia

No se porque querrias heredar ostream, pero no me importa. Es posible con FILE

class MyFile : public FILE {}

Tipo de seguridad

Es cierto que las listas de argumentos de longitud variable no tienen seguridad, pero eso no importa, ya que los compiladores populares de C pueden detectar problemas con printf formato de cadena si habilita las advertencias. De hecho, Clang puede hacer eso sin habilitar las advertencias.

$ cat safety.c

#include <stdio.h>

int main(void) {
    printf("String: %s\n", 42);
    return 0;
}

$ clang safety.c

safety.c:4:28: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
    printf("String: %s\n", 42);
                    ~~     ^~
                    %d
1 warning generated.
$ gcc -Wall safety.c
safety.c: In function ‘main’:
safety.c:4:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
     printf("String: %s\n", 42);
     ^

Respondido el 19 de junio de 18 a las 09:06

De todos modos, dices que la E / S es el cuello de botella. Obviamente tu nunca probado esa suposición. Me cito a mí mismo: "Por otro lado, la versión de iostreams, a 75.3 MB / s, no puede almacenar datos en el búfer lo suficientemente rápido como para mantenerse al día con un disco duro. Eso es malo, y ni siquiera está haciendo ningún trabajo real todavía. Creo que tengo expectativas demasiado altas cuando digo que mi biblioteca de E / S debería poder saturar mi controlador de disco ". - ben voigt

@BenVoigt: Lo admito, trato de evitar C ++ cuando es posible. Intenté usarlo mucho, pero era más molesto y menos fácil de mantener que otros lenguajes de programación que usé. Esta es otra razón más para evitar C ++; esto ni siquiera es rápido (ni siquiera es iostream; toda la biblioteca de C ++ es lenta en la mayoría de las implementaciones, tal vez con la excepción de std::sort, que de alguna manera es sorprendentemente rápido en comparación con qsort (2 veces), a costa del tamaño del ejecutable). - Konrad Borowski

Nadie aquí ha mencionado problemas en el entorno paralelo al usar cout. - Nicolás Hamilton

Su argumento de rendimiento no tiene ningún sentido. Más ensamblaje en su programa no significa que el programa será más lento, porque está no teniendo en cuenta todo el código que hace que la función printf, que es mucho código. En mi opinión, es posible optimizar cout con el operador << mucho mejor que el printf, porque el compilador puede entender mejor las variables y el formato. - Ignas2526

Me gustan muchas cosas de esta respuesta, pero quizás mi parte favorita es "Todos piensan que se preocupan por el rendimiento, pero nadie se molesta en medirlo". - hebra kyle

Desde el Preguntas frecuentes de C ++:

[15.1] ¿Por qué debería usar <iostream> en lugar de lo tradicional <cstdio>?

Aumente la seguridad de los tipos, reduzca los errores, permita la extensibilidad y proporcione heredabilidad.

printf() podría decirse que no está roto, y scanf() es quizás habitable a pesar de ser propenso a errores, sin embargo, ambos están limitados con respecto a lo que C ++ I / O puede hacer. E / S de C ++ (usando << y >>) es, relativo a C (usando printf() y scanf()):

  • Más seguro de tipos: con <iostream>, el compilador conoce estáticamente el tipo de objeto que se está realizando en E / S. A diferencia de, <cstdio> utiliza campos "%" para averiguar los tipos de forma dinámica.
  • Menos propenso a errores: con <iostream>, no hay tokens "%" redundantes que tengan que ser consistentes con los objetos reales que se están realizando en E / S. Eliminar la redundancia elimina una clase de errores.
  • Extensible: el C ++ <iostream> El mecanismo permite la E / S de nuevos tipos definidos por el usuario sin romper el código existente. Imagínese el caos si todos estuvieran agregando simultáneamente nuevos campos "%" incompatibles a printf() y scanf()?!
  • Heredable: el C ++ <iostream> El mecanismo se construye a partir de clases reales como std::ostream y std::istream. diferente a <cstdio>'s FILE*, estas son clases reales y, por lo tanto, heredables. Esto significa que puede tener otras cosas definidas por el usuario que se ven y actúan como transmisiones, pero que hacen las cosas extrañas y maravillosas que desee. Automáticamente puede usar los miles de millones de líneas de código de E / S escritas por usuarios que ni siquiera conoce, y ellos no necesitan saber acerca de su clase de "flujo extendido".

Por otra parte, printf es significativamente más rápido, lo que puede justificar su uso en lugar de cout in Casos específicos y limitados. Siempre perfil primero. (Ver, por ejemplo, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout/)

Respondido el 09 de diciembre de 17 a las 11:12

Por otro lado, está la biblioteca FastFormat (fastformat.org), ofreciendo seguridad de tipografía, expresividad y rendimiento a la vez. (No es que lo haya probado todavía ...) - xtofl

@Marcelo probablemente porque es un buen resumen, con todo citado. El formato ... sí, eso es bastante malo. Debería haberlo arreglado yo mismo, pero parece que otros (incluido usted mismo) se encargaron de ello, lo que, por supuesto, es más constructivo que solo quejarse. - mikeage

Últimamente printf() también se supone que es extensible. Ver "ganchos printf" en udrepper.livejournal.com/20948.html - Maxim Egorushkin

@MaximYegorushkin: Estándar printf no tiene tal habilidad. Los mecanismos de biblioteca no portátiles difícilmente están al mismo nivel que la extensibilidad completamente estandarizada de iostreams. - ben voigt

"Por otro lado, printf es significativamente más rápido" printf también es más limpio y más fácil de usar, por lo que evito cout cuando sea posible. - FluorescenteVerde5

La gente suele afirmar que printf es mucho más rápido. Esto es en gran parte un mito. Lo acabo de probar, con los siguientes resultados:

cout with only endl                     1461.310252 ms
cout with only '\n'                      343.080217 ms
printf with only '\n'                     90.295948 ms
cout with string constant and endl      1892.975381 ms
cout with string constant and '\n'       416.123446 ms
printf with string constant and '\n'     472.073070 ms
cout with some stuff and endl           3496.489748 ms
cout with some stuff and '\n'           2638.272046 ms
printf with some stuff and '\n'         2520.318314 ms

Conclusión: si solo desea nuevas líneas, use printf; de otra manera, cout es casi tan rápido, o incluso más rápido. Se pueden encontrar más detalles en mi blog.

Para ser claro, no estoy tratando de decir eso. iostreams son siempre mejores que printf; Solo estoy tratando de decir que debe tomar una decisión informada basada en datos reales, no una suposición descabellada basada en alguna suposición común y engañosa.

Actualización: Aquí está el código completo que usé para probar. Compilado con g++ sin opciones adicionales (aparte de -lrt para el momento).

#include <stdio.h>
#include <iostream>
#include <ctime>

class TimedSection {
    char const *d_name;
    timespec d_start;
    public:
        TimedSection(char const *name) :
            d_name(name)
        {
            clock_gettime(CLOCK_REALTIME, &d_start);
        }
        ~TimedSection() {
            timespec end;
            clock_gettime(CLOCK_REALTIME, &end);
            double duration = 1e3 * (end.tv_sec - d_start.tv_sec) +
                              1e-6 * (end.tv_nsec - d_start.tv_nsec);
            std::cerr << d_name << '\t' << std::fixed << duration << " ms\n"; 
        }
};

int main() {
    const int iters = 10000000;
    char const *text = "01234567890123456789";
    {
        TimedSection s("cout with only endl");
        for (int i = 0; i < iters; ++i)
            std::cout << std::endl;
    }
    {
        TimedSection s("cout with only '\\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << '\n';
    }
    {
        TimedSection s("printf with only '\\n'");
        for (int i = 0; i < iters; ++i)
            printf("\n");
    }
    {
        TimedSection s("cout with string constant and endl");
        for (int i = 0; i < iters; ++i)
            std::cout << "01234567890123456789" << std::endl;
    }
    {
        TimedSection s("cout with string constant and '\\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << "01234567890123456789\n";
    }
    {
        TimedSection s("printf with string constant and '\\n'");
        for (int i = 0; i < iters; ++i)
            printf("01234567890123456789\n");
    }
    {
        TimedSection s("cout with some stuff and endl");
        for (int i = 0; i < iters; ++i)
            std::cout << text << "01234567890123456789" << i << std::endl;
    }
    {
        TimedSection s("cout with some stuff and '\\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << text << "01234567890123456789" << i << '\n';
    }
    {
        TimedSection s("printf with some stuff and '\\n'");
        for (int i = 0; i < iters; ++i)
            printf("%s01234567890123456789%i\n", text, i);
    }
}

contestado el 20 de mayo de 10 a las 13:05

En sus partituras, printf gana fácilmente a cout (mayoría de los casos). Me pregunto por qué recomienda usar cout cuando se trata de perf. Aunque estoy de acuerdo, perf no es muy diferente en casos realistas .. - mishal153

@ mishal153: Solo estoy tratando de decir que el rendimiento no es muy diferente, por lo que el consejo comúnmente escuchado de "nunca uses cout porque es muy lento" es simplemente estúpido. Tenga en cuenta que cout tiene la ventaja obvia de la seguridad de tipos y, a menudo, también la legibilidad. (El formato de punto flotante con iostreams es horrible ...) - Thomas

La importante diferencia entre printf() y std::ostream es que el primero genera todos los argumentos en una sola llamada mientras std::ostream incurre en una llamada separada para cada <<. La prueba solo genera un argumento y una nueva línea, por eso no puede ver la diferencia. - Maxim Egorushkin

El compilador debería poder integrar estas llamadas. También, printf podría hacer muchas llamadas ocultas a funciones auxiliares para varios especificadores de formato ... eso, o es una función monolítica monstruosa. Y nuevamente, debido a la alineación, no debería hacer una diferencia en la velocidad en absoluto. - Thomas

Has cronometrado tu terminal. Usar sprintf or fprintf y stringstream or fstream. - ben voigt

Y yo cotización inicial:

En términos de alto nivel, las principales diferencias son la seguridad de tipos (cstdio no lo tiene), el rendimiento (la mayoría de las implementaciones de iostreams son más lentas que las de cstdio) y la extensibilidad (iostreams permite objetivos de salida personalizados y una salida perfecta de tipos definidos por el usuario).

contestado el 20 de mayo de 10 a las 10:05

Especialmente en unix, donde con POSIX nunca se sabe qué tamaño tiene realmente una de las typedefs, por lo que necesita muchas conversiones o como el 99% de los programas simplemente se arriesga con% d. Pasó incluso mucho tiempo antes de que% z viniera con C99. Pero para time_t / off_t continúa la búsqueda de la instrucción de formato correcta. - Lothar

Una es una función que se imprime en la salida estándar. El otro es un objeto que proporciona varias funciones miembro y sobrecargas de operator<< esa impresión a la salida estándar. Hay muchas más diferencias que podría enumerar, pero no estoy seguro de lo que buscas.

Respondido 04 Feb 13, 03:02

Para mí, las diferencias reales que me harían elegir 'cout' en lugar de 'printf' son:

1) << El operador puede estar sobrecargado para mis clases.

2) El flujo de salida para cout se puede cambiar fácilmente a un archivo: (: copiar y pegar :)

#include <iostream>
#include <fstream>
using namespace std;

int main ()
{
    cout << "This is sent to prompt" << endl;
    ofstream file;
    file.open ("test.txt");
    streambuf* sbuf = cout.rdbuf();
    cout.rdbuf(file.rdbuf());
    cout << "This is sent to file" << endl;
    cout.rdbuf(sbuf);
    cout << "This is also sent to prompt" << endl;
    return 0;
}

3) Encuentro cout más legible, especialmente cuando tenemos muchos parámetros.

Una problema con cout son las opciones de formato. Formatear los datos (precisión, justificación, etc.) en printf es mas facil.

Respondido el 28 de junio de 10 a las 18:06

es agradable. ¿Cómo puedo saber que nadie modifica el cout global de esta manera en algún hilo de biblioteca ajeno? - vp_arth

Puedes cambiar fácilmente printf a un archivo también reemplazándolo con fprintf... - CaféMesaEspresso

Dos puntos que no se mencionan de otra manera aquí que me parecen significativos:

1) cout lleva mucho equipaje si aún no está usando el STL. Agrega más del doble de código a su archivo de objeto que printf. Esto también es cierto para string, y esta es la razón principal por la que tiendo a usar mi propia biblioteca de cadenas.

2) cout utiliza sobrecargado << operadores, lo que me parece desafortunado. Esto puede agregar confusión si también está usando el << operador para su propósito previsto (desplazamiento a la izquierda). Personalmente, no me gusta sobrecargar a los operadores con fines tangenciales a su uso previsto.

En pocas palabras: usaré cout (y string) si ya estoy usando STL. De lo contrario, tiendo a evitarlo.

Respondido el 05 de diciembre de 14 a las 21:12

Con las primitivas, probablemente no importa del todo cuál uses. Digo que lo que obtiene utilidad es cuando desea generar objetos complejos.

Por ejemplo, si tienes una clase,

#include <iostream>
#include <cstdlib>

using namespace std;

class Something
{
public:
        Something(int x, int y, int z) : a(x), b(y), c(z) { }
        int a;
        int b;
        int c;

        friend ostream& operator<<(ostream&, const Something&);
};

ostream& operator<<(ostream& o, const Something& s)
{
        o << s.a << ", " << s.b << ", " << s.c;
        return o;
}

int main(void)
{
        Something s(3, 2, 1);

        // output with printf
        printf("%i, %i, %i\n", s.a, s.b, s.c);

        // output with cout
        cout << s << endl;

        return 0;
}

Ahora bien, lo anterior puede no parecer tan bueno, pero supongamos que tiene que generar esto en varios lugares de su código. No solo eso, digamos que agrega un campo "int d". Con cout, solo tienes que cambiarlo en un lugar. Sin embargo, con printf, posiblemente tendrías que cambiarlo en muchos lugares y no solo eso, tienes que recordarte a ti mismo cuáles imprimir.

Dicho esto, con cout, puede reducir una gran cantidad de tiempo dedicado al mantenimiento de su código y no solo eso si reutiliza el objeto "Algo" en una nueva aplicación, realmente no tiene que preocuparse por la salida.

contestado el 20 de mayo de 10 a las 19:05

Además, para agregar sobre el rendimiento, diría que no debería generar nada en absoluto si su aplicación está hecha para el rendimiento. Cualquier tipo de salida a std es bastante cara y lenta. Yo digo que debe evitarlo y publicar solo cuando sea absolutamente necesario hacerlo. - Daniel

Tenga en cuenta que su clase puede tener miembros privados a los que no puede acceder tan fácilmente desde el exterior. Con el operador de salida, tiene exactamente una ubicación que debe ser amiga de su clase, y ahora puede generarla en cualquier lugar, incluso en un código que no conocía. - hochl

Por supuesto, puede escribir "algo" un poco mejor para mantener el mantenimiento:

#include <iostream>
#include <cstdlib>

using namespace std;

class Something
{
    public:
        Something(int x, int y, int z) : a(x), b(y), c(z) { }
        int a;
        int b;
        int c;

        friend ostream& operator<<(ostream&, const Something&);

        void print() const { printf("%i, %i, %i\n", a, b, c); }
};

ostream& operator<<(ostream& o, const Something& s)
{
    o << s.a << ", " << s.b << ", " << s.c;
    return o;
}

int main(void)
{
    Something s(3, 2, 1);

    // Output with printf
    s.print(); // Simple as well, isn't it?

    // Output with cout
    cout << s << endl;

    return 0;
}

Y una prueba un poco extendida de cout vs. printf, agregada una prueba de 'doble', si alguien quiere hacer más pruebas (Visual Studio 2008, versión de lanzamiento del ejecutable):

#include <stdio.h>
#include <iostream>
#include <ctime>

class TimedSection {
    char const *d_name;
    //timespec d_start;
    clock_t d_start;

    public:
        TimedSection(char const *name) :
            d_name(name)
        {
            //clock_gettime(CLOCK_REALTIME, &d_start);
            d_start = clock();
        }
        ~TimedSection() {
            clock_t end;
            //clock_gettime(CLOCK_REALTIME, &end);
            end = clock();
            double duration = /*1e3 * (end.tv_sec - d_start.tv_sec) +
                              1e-6 * (end.tv_nsec - d_start.tv_nsec);
                              */
                              (double) (end - d_start) / CLOCKS_PER_SEC;

            std::cerr << d_name << '\t' << std::fixed << duration * 1000.0 << " ms\n";
        }
};


int main() {
    const int iters = 1000000;
    char const *text = "01234567890123456789";
    {
        TimedSection s("cout with only endl");
        for (int i = 0; i < iters; ++i)
            std::cout << std::endl;
    }
    {
        TimedSection s("cout with only '\\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << '\n';
    }
    {
        TimedSection s("printf with only '\\n'");
        for (int i = 0; i < iters; ++i)
            printf("\n");
    }
    {
        TimedSection s("cout with string constant and endl");
        for (int i = 0; i < iters; ++i)
            std::cout << "01234567890123456789" << std::endl;
    }
    {
        TimedSection s("cout with string constant and '\\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << "01234567890123456789\n";
    }
    {
        TimedSection s("printf with string constant and '\\n'");
        for (int i = 0; i < iters; ++i)
            printf("01234567890123456789\n");
    }
    {
        TimedSection s("cout with some stuff and endl");
        for (int i = 0; i < iters; ++i)
            std::cout << text << "01234567890123456789" << i << std::endl;
    }
    {
        TimedSection s("cout with some stuff and '\\n'");
        for (int i = 0; i < iters; ++i)
            std::cout << text << "01234567890123456789" << i << '\n';
    }
    {
        TimedSection s("printf with some stuff and '\\n'");
        for (int i = 0; i < iters; ++i)
            printf("%s01234567890123456789%i\n", text, i);
    }
    {
        TimedSection s("cout with formatted double (width & precision once)");
        std::cout << std::fixed << std::scientific << std::right << std::showpoint;
        std::cout.width(8);
        for (int i = 0; i < iters; ++i)
            std::cout << text << 8.315 << i << '\n';
    }
    {
        TimedSection s("cout with formatted double (width & precision on each call)");
        std::cout << std::fixed << std::scientific << std::right << std::showpoint;

        for (int i = 0; i < iters; ++i)
            { std::cout.width(8);
              std::cout.precision(3);
              std::cout << text << 8.315 << i << '\n';
            }
    }
    {
        TimedSection s("printf with formatted double");
        for (int i = 0; i < iters; ++i)
            printf("%8.3f%i\n", 8.315, i);
    }
}

El resultado es:

cout with only endl    6453.000000 ms
cout with only '\n'    125.000000 ms
printf with only '\n'    156.000000 ms
cout with string constant and endl    6937.000000 ms
cout with string constant and '\n'    1391.000000 ms
printf with string constant and '\n'    3391.000000 ms
cout with some stuff and endl    9672.000000 ms
cout with some stuff and '\n'    7296.000000 ms
printf with some stuff and '\n'    12235.000000 ms
cout with formatted double (width & precision once)    7906.000000 ms
cout with formatted double (width & precision on each call)    9141.000000 ms
printf with formatted double    3312.000000 ms

contestado el 22 de mayo de 17 a las 22:05

Wow, ¿por qué es endl mucho menos eficiente que '\n'? - Nicolás Hamilton

Creo que es porque endl limpia el búfer y \n no lo hace, aunque no estoy seguro de que esta sea definitivamente la razón. - caleb

Esta no es una respuesta a la pregunta, es más como una respuesta a Daniel's y De Thomas. - Fabio dice Reincorporar a Monica

Me gustaría señalar que si quieres jugar con subprocesos en C ++, si usas cout puedes obtener algunos resultados interesantes.

Considere este código:

#include <string>
#include <iostream>
#include <thread>

using namespace std;

void task(int taskNum, string msg) {
    for (int i = 0; i < 5; ++i) {
        cout << "#" << taskNum << ": " << msg << endl;
    }
}

int main() {
    thread t1(task, 1, "AAA");
    thread t2(task, 2, "BBB");
    t1.join();
    t2.join();
    return 0;
}

// g++ ./thread.cpp -o thread.out -ansi -pedantic -pthread -std=c++0x

Ahora, la salida viene de forma aleatoria. También puede producir resultados diferentes, intente ejecutar varias veces:

##12::  ABABAB

##12::  ABABAB

##12::  ABABAB

##12::  ABABAB

##12::  ABABAB

Puede usar el printf para hacerlo bien, o puede usar mutex.

#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB
#1: AAA
#2: BBB

¡Que se diviertan!

Respondido 28 Jul 17, 14:07

wtf threads no hacen que la salida se vuelva loca. Me acabo de reproducir y encontré ambos xyz y ABC en la salida. No hubo destrozos b / w ABC as ABABAB. - Abhinav Gauniyal

No se como cout funciona con subprocesos, pero estoy seguro de que el código que está mostrando no es el que usó para obtener esos resultados. Tu código pasa la cadena "ABC" para el hilo 1 y "xyz" para el hilo 2, pero su salida muestra AAA y BBB. Por favor, corríjalo, porque ahora mismo es confuso. - Fabio dice Reincorporar a Monica

cout<< "Hello";
printf("%s", "Hello"); 

Ambos se utilizan para imprimir valores. Tienen una sintaxis completamente diferente. C ++ tiene ambos, C solo tiene printf.

Respondido el 04 de Septiembre de 10 a las 21:09

... ¿qué? confundiste algo? - xtofl

Se solucionó el problema. -1 porque requirió corrección y la respuesta deja mucho que desear. - Yacoby

Los nombres de las funciones se habían invertido: cout se usaba con la sintaxis printf y printf se usaba con la sintaxis cout. ¡Ni siquiera debería haber sido aceptado! - Mahmoud Al-Qudsi

y la principal desventaja de cout es que usa operator << que es verboso y feo y posiblemente abuso de operador. :) - jalf

Aunque esta certeza no es la mejor respuesta, no entiendo cómo se está castigando a Scatman por su respuesta solo porque fue elegida como la mejor respuesta. xbit tiene una respuesta mucho peor en mi opinión, pero tiene -1 voto. No estoy diciendo que xbit deba volver a ser rechazado, pero no veo que sea justo rechazar a scatman por el error del OP más de lo que tiene que ser ... - Jesse

Me gustaría decir que la falta de extensibilidad printf no es del todo cierto:
En C, es cierto. Pero en C, no hay clases reales.
En C ++, es posible sobrecargar el operador de conversión, por lo que sobrecargar un char* operador y usando printf Me gusta esto:

Foo bar;
...;
printf("%s",bar);

puede ser posible, si Foo sobrecarga al buen operador. O si hiciste un buen método. En breve, printf es tan extensible como cout para mí.

Los argumentos técnicos que puedo ver para las transmisiones de C ++ (en general ... no solo cout.) Son:

  • Typesafety. (Y, por cierto, si quiero imprimir una sola '\n' yo suelo putchar('\n')... No usaré una bomba nuclear para matar un insecto).

  • Más sencillo de aprender. (no hay parámetros "complicados" que aprender, solo usar << y >> operadores)

  • Trabaja de forma nativa con std::string (solo para printf hay std::string::c_str(), pero para scanf?)

Para printf Veo:

  • Formato complejo más fácil, o al menos más corto (en términos de caracteres escritos). Mucho más legible para mí (cuestión de gustos, supongo).

  • Mejor control de lo que hizo la función (devuelva cuántos caracteres se escribieron y %n formateador: "Nada impreso. El argumento debe ser un puntero a un int firmado, donde se almacena el número de caracteres escritos hasta ahora". (de printf - Referencia de C ++)

  • Mejores posibilidades de depuración. Por la misma razón que el último argumento.

Mis preferencias personales van a printf (y scanf), principalmente porque me encantan las líneas cortas y porque no creo que los problemas de tipografía al imprimir texto sean realmente difíciles de evitar. Lo único que deploro con las funciones de estilo C es que std::string no es apoyado. Tenemos que pasar por un char* antes de dárselo a printf (Con la std::string::c_str() si queremos leer, pero ¿cómo escribir?)

Respondido el 11 de enero de 12 a las 10:01

El compilador no tiene información de tipo para las funciones de varargs, por lo que no convertirá el parámetro real (excepto promociones de argumentos predeterminados, como promociones integrales estándar). Ver 5.2.2p7. Una conversión definida por el usuario a char* no se utilizará. - ben voigt

Incluso si esto funcionara, no sería un ejemplo de extensibilidad de sprintf, solo un truco inteligente para darle a sprintf lo que espera, e ignora algunos problemas serios como dónde está char* vidas y por cuánto tiempo, y los peligros de las conversiones implícitas definidas por el usuario. - marcelo cantos

Más diferencias: "printf" devuelve un valor entero (igual al número de caracteres impresos) y "cout" no devuelve nada

Y.

cout << "y = " << 7; no es atómico.

printf("%s = %d", "y", 7); es atómico.

cout realiza la verificación de tipo, printf no.

No hay equivalente en iostream de "% d"

Respondido el 27 de diciembre de 12 a las 16:12

cout no devuelve nada porque es un objeto, no una función. operator<< devuelve algo (normalmente su operando izquierdo, pero un valor falso si hay un error). Y en que sentido es el printf llamar "atómico"? - Keith Thompson

Es como una bomba atómica. printf("%s\n",7); - ruido ingenuo

@artlessnoise espera ¿por qué falla la segmentación? %s es ? - Abhinav Gauniyal

Ese es el punto de la declaración de la "bomba atómica". A printf %s El argumento debe tener un puntero válido a una cadena terminada en nulo. El rango de memoria '7' (un puntero) no suele ser válido; una falla de segmentación podría tener suerte. En algunos sistemas, '7' podría imprimir mucha basura en una consola y tendría que mirarla durante un día antes de que el programa se detenga. En otras palabras, esto es algo malo sobre printf. Las herramientas de análisis estático pueden detectar muchos de estos problemas. - ruido ingenuo

Aunque técnicamente printf no realiza verificación de tipo, nunca he usado un compilador que no me advirtiera sobre errores de tipo con printf... - CaféMesaEspresso

TL; DR: Siempre haga su propia investigación, con respecto a tamaño de código de máquina generado, actuación, legibilidad y tiempo de codificación antes de confiar en los comentarios aleatorios en línea, incluido este.

No soy un experto. Por casualidad escuché a dos compañeros de trabajo hablar sobre cómo deberíamos evitar el uso de C ++ en sistemas integrados debido a problemas de rendimiento. Bueno, bastante interesante, hice un punto de referencia basado en una tarea de proyecto real.

En dicha tarea, tuvimos que escribir alguna configuración en la RAM. Algo como:

cafe = caliente
azúcar = ninguno
leche = pecho
mac = AA: BB: CC: DD: EE: FF

Aquí están mis programas de referencia (Sí, sé que OP preguntó sobre printf (), no fprintf (). Intente capturar la esencia y, por cierto, el enlace de OP apunta a fprintf () de todos modos).

Programa C:

char coffee[10], sugar[10], milk[10];
unsigned char mac[6];

/* Initialize those things here. */

FILE * f = fopen("a.txt", "wt");

fprintf(f, "coffee=%s\nsugar=%s\nmilk=%s\nmac=%02X:%02X:%02X:%02X:%02X:%02X\n", coffee, sugar, milk, mac[0], mac[1],mac[2],mac[3],mac[4],mac[5]);

fclose(f);

Programa C ++:

//Everything else is identical except:

std::ofstream f("a.txt", std::ios::out);

f << "coffee=" << coffee << "\n";
f << "sugar=" << sugar << "\n";
f << "milk=" << milk << "\n";
f << "mac=" << (int)mac[0] << ":"
    << (int)mac[1] << ":"
    << (int)mac[2] << ":"
    << (int)mac[3] << ":"
    << (int)mac[4] << ":"
    << (int)mac[5] << endl;
f.close();

Hice todo lo posible para pulirlos antes de enrollarlos a ambos 100,000 veces. Aquí están los resultados:

Programa C:

real    0m 8.01s
user    0m 2.37s
sys     0m 5.58s

Programa C ++:

real    0m 6.07s
user    0m 3.18s
sys     0m 2.84s

Tamaño del archivo de objeto:

C   - 2,092 bytes
C++ - 3,272 bytes

Conclusión: en mi muy específico plataforma, con un muy específico procesador, ejecutando una versión muy específica de Kernel Linux, para ejecutar un programa que está compilado con una versión muy específica de GCC, con el fin de lograr un muy específico tarea, Yo diría que el enfoque de C ++ es más adecuado porque se ejecuta significativamente más rápido y proporciona una legibilidad mucho mejor. Por otro lado, C ofrece una huella pequeña, en mi opinión, no significa casi nada porque el tamaño del programa no es de nuestra incumbencia.

Recuerda, YMMV.

Respondido 01 Abr '17, 06:04

No estoy de acuerdo con que C ++ sea más legible en este ejemplo, porque su ejemplo empaqueta varias líneas en una sola llamada a printf. Eso es, naturalmente, menos legible que la forma en que hizo el código C ++, y rara vez se hace en C porque es difícil de leer y de mantener. Una comparación justa distribuiría la C en printfs separados, uno para la línea de alcance. - maharvey67

@ maharvey67 Es cierto lo que dijiste. Sin embargo, el ejemplo que proporcioné en C fue en consideración al desempeño. La llamada empaquetada en uno a fprintf fue dos segundos más lenta que la equivalencia de C ++. Si tuviera que hacer que el código C fuera legible, podría ser incluso más lento. Descargo de responsabilidad: esto fue hace un año y recuerdo que hice todo lo posible para pulir el código C y C ++. No tenía pruebas de que las llamadas separadas a fprintf fueran más rápidas que una sola llamada, pero la razón por la que lo hice de esta manera probablemente indica que no lo fue. - Wesley

No soy programador, pero he sido ingeniero de factores humanos. Siento que un lenguaje de programación debe ser fácil de aprender, comprender y usar, y esto requiere que tenga una estructura lingüística simple y consistente. Aunque todos los idiomas son simbólicos y, por lo tanto, en su esencia, arbitrarios, existen convenciones y seguirlas hace que el idioma sea más fácil de aprender y usar.

Hay una gran cantidad de funciones en C ++ y otros lenguajes escritos como función (parámetro), una sintaxis que se usó originalmente para las relaciones funcionales en matemáticas en la era anterior a la computadora. printf() sigue esta sintaxis y si los escritores de C ++ quisieran crear cualquier método lógicamente diferente para leer y escribir archivos, simplemente podrían haber creado una función diferente usando una sintaxis similar.

En Python, por supuesto, podemos imprimir utilizando el también bastante estándar object.method sintaxis, es decir, variablename.print, ya que las variables son objetos, pero en C ++ no lo son.

No me gusta la sintaxis cout porque el operador << no sigue ninguna regla. Es un método o función, es decir, toma un parámetro y le hace algo. Sin embargo, está escrito como si fuera un operador de comparación matemática. Este es un enfoque deficiente desde el punto de vista de los factores humanos.

contestado el 25 de mayo de 17 a las 18:05

printf es una función mientras que cout es una variable

Respondido el 18 de junio de 18 a las 14:06

Hice una reversión porque, aunque la respuesta en sí misma puede ser incorrecta, sigue siendo una respuesta genuina. Si cree (correctamente) que la respuesta es incorrecta, tiene dos opciones: 1) agregar un comentario o 2) agregar una nueva respuesta (o hacer ambas cosas). No cambie la respuesta de alguien a tal que diga algo completamente diferente de lo que pretendía el autor. - Mark

printf es una función, pero printf() es una llamada de función =) - vp_arth

cout es un objeto, no una variable. - Lin

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.