sirve - ''printf'' vs. ''cout'' en C++
Con los primitivos, probablemente no importa por completo cuál uses. Digo que la utilidad resulta cuando se quieren 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, lo anterior puede que no parezca tan bueno, pero supongamos que tiene que generar esto en múltiples lugares en su código. No solo eso, digamos que agrega un campo "int d". Con cout, solo tienes que cambiarlo en un solo lugar. Sin embargo, con printf, tendrías que cambiarlo posiblemente en muchos lugares y no solo eso, debes recordarte cuáles son los resultados.
Dicho esto, con cout, puede reducir la cantidad de veces que dedica al mantenimiento de su código y no solo eso, si reutiliza el objeto "Algo" en una nueva aplicación, no tiene que preocuparse realmente por el resultado.
De las preguntas frecuentes de C ++ :
[15.1] ¿Por qué debería usar
<iostream>
lugar del tradicional<cstdio>
?Aumente la seguridad de los tipos, reduzca los errores, permita la extensibilidad y proporcione heredabilidad.
printf()
no está roto, yscanf()
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. C ++ I / O (con<<
y>>
) es, en relación con C (conprintf()
yscanf()
):
- Más seguro para el tipo: con
<iostream>
, el compilador conoce estáticamente el tipo de objeto que tiene E / S. En contraste,<cstdio>
usa los campos "%" para determinar los tipos de forma dinámica.- Menos propenso a errores: con
<iostream>
, no hay tokens "%" redundantes que deban ser coherentes con los objetos reales que son E / S. Eliminar la redundancia elimina una clase de errores.- Extensible: el mecanismo de C ++
<iostream>
permite que los nuevos tipos definidos por el usuario sean I / O''d sin romper el código existente. ¡Imagínese el caos si todos agregaran simultáneamente nuevos campos "%" incompatibles aprintf()
yscanf()
?- Heredable: El mecanismo de C ++
<iostream>
se construye a partir de clases reales comostd::ostream
ystd::istream
. A diferencia delFILE*
<cstdio>
, estas son clases reales y, por lo tanto, heredadas. Esto significa que puedes tener otras cosas definidas por el usuario que se ven y actúan como secuencias, pero que hacen las cosas extrañas y maravillosas que deseas. Automáticamente puede usar las millones de líneas de código de E / S escritas por usuarios que ni siquiera conoce, y no necesitan saber sobre su clase de "flujo extendido".
Por otro lado, printf
es significativamente más rápido, lo que puede justificar su uso con preferencia a cout
en casos muy específicos y limitados. Siempre perfil primero. (Ver, por ejemplo, http://programming-designs.com/2009/02/c-speed-test-part-2-printf-vs-cout /)
Dos puntos no mencionados aquí de otra manera que me parecen significativos:
1) cout
lleva una gran cantidad de equipaje si aún no está utilizando el STL. Agrega más del doble de código a tu archivo de objeto que printf
. Esto también es cierto para la string
, y esta es la razón principal por la que tiendo a usar mi propia biblioteca de cadenas.
2) cout
utiliza operadores <<
sobrecargados, lo que me parece desafortunado. Esto puede agregar confusión si también está utilizando 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.
Línea inferior: cout
(y string
) si ya estoy usando la STL. De lo contrario, tiendo a evitarlo.
La gente suele afirmar que printf
es mucho más rápido. Esto es en gran parte un mito. Acabo de probarlo, 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 quieres nuevas líneas, usa printf
; de lo contrario, cout
es casi tan rápido, o incluso más rápido. Más detalles se pueden encontrar en mi blog .
Para ser claros, no estoy tratando de decir que los iostream
son siempre mejores que printf
; Solo trato de decir que debe tomar una decisión informada basada en datos reales, no en una suposición descabellada basada en una suposición común y engañosa.
Actualización: Aquí está el código completo que usé para las pruebas. Compilado con g++
sin ninguna opción adicional (aparte de -lrt
para el tiempo).
#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);
}
}
Me gustaría decir que la falta de extensibilidad de 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 tanto, sobrecargar un operador char*
y usar printf
siguiente manera:
Foo bar;
...;
printf("%s",bar);
Puede ser posible, si Foo sobrecarga al buen operador. O si hiciste un buen método. En resumen, printf
es tan extensible como cout
para mí.
El argumento técnico que puedo ver para las secuencias de C ++ (en general ... no solo cout.) Son:
Tipos de seguridad. (Y, por cierto, si quiero imprimir un solo
''/n''
usoputchar(''/n'')
... no usaré una bomba nuclear para matar a un insecto).Más sencillo de aprender. (no hay parámetros "complicados" que aprender, solo usar los operadores
<<
y>>
)Trabaja de forma nativa con
std::string
(paraprintf
existestd::string::c_str()
, pero parascanf
?)
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 está el formateador
%n
: "No se imprime nada. 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 el mismo motivo que el último argumento.
Mis preferencias personales van a las funciones printf
(y scanf
), principalmente porque me encantan las líneas cortas y porque no creo que los problemas de tipografía en la impresión de texto sean realmente difíciles de evitar. Lo único que lamento con las funciones de estilo C es que std::string
no es compatible. Tenemos que pasar por un char*
antes de dárselo a printf
(con std::string::c_str()
si queremos leer, pero ¿cómo escribir?)
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 todo barajado. También puede producir diferentes resultados, intente ejecutar varias veces:
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
##12:: ABABAB
Puede usar 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 te diviertas!
Me sorprende que todos en esta pregunta afirmen que std::cout
es mucho mejor que printf
, incluso si la pregunta solo plantea diferencias. Ahora, hay una diferencia: std::cout
es C ++ y printf
es C (sin embargo, puedes usarlo en C ++, como cualquier otra cosa de C). Ahora, seré honesto aquí; Tanto printf
como std::cout
tienen sus ventajas.
Diferencias reales
Extensibilidad
std::cout
es extensible. Sé que la gente dirá que printf
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. carta (por lo que es fácil entrar en conflicto con un formato ya existente).
A diferencia de printf
, std::cout
depende completamente de la sobrecarga del operador, por lo que no hay problema con los formatos personalizados; todo lo que debe hacer es definir una subrutina que tome std::ostream
como primer argumento y su tipo como segundo. Como tal, no hay problemas con el espacio de nombres; mientras tengas una clase (que no se limita a un solo carácter), puedes tener la sobrecarga de std::ostream
para ello.
Sin embargo, dudo que muchas personas quieran extender ostream
(para ser honesto, rara vez vi tales extensiones, incluso si son fáciles de hacer). Sin embargo, está aquí si lo necesitas.
Sintaxis
Como se pudo notar fácilmente, tanto printf
como std::cout
utilizan una sintaxis diferente. printf
usa la sintaxis de la función estándar usando una cadena de patrones y listas de argumentos de longitud variable. En realidad, printf
es una de las razones por las que C los tiene: los formatos de printf
son demasiado complejos para poder usarse sin ellos. Sin embargo, std::cout
usa una API diferente: la API del operator <<
que se devuelve a sí misma.
En general, eso significa que la versión C será más corta, pero en la mayoría de los casos no importará. La diferencia es notable cuando imprime muchos argumentos. Si tiene 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 funcionan de manera idéntica (bueno, más o menos, std::endl
realidad std::endl
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 en realidad formateas los argumentos, en lugar de solo imprimirlos. Por ejemplo, la impresión de algo como 0x0424
es una locura. Esto es causado por el estado de mezcla std::cout
y los valores reales. Nunca vi un lenguaje donde algo como std::setfill
sería un tipo (aparte de C ++, por supuesto). printf
separa claramente los argumentos y el tipo real. Realmente preferiría mantener la versión de printf
(incluso si parece algo críptica) en comparación con la versión de iostream
(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 radica la verdadera ventaja de printf
. La printf
formato printf
es bien ... una cadena. Eso hace que sea realmente fácil de traducir, en comparación con el abuso de iostream
del operator <<
. Suponiendo que la función gettext()
traduce, y desea 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, asumamos que traducimos a Fictionish, donde el número de error está después de la descripción. La cadena traducida se vería como %2$s oru %1$d./n
Ahora, ¿cómo hacerlo en C ++? Bueno, no tengo ni idea. Supongo que puedes hacer iostream
falso que construye printf
que puedes pasar a gettext
, o algo así, para propósitos de traducción. Por supuesto, $
no es un estándar de C, pero es tan común que es seguro de usar en mi opinión.
No tener que recordar / buscar sintaxis de tipo entero específico
C tiene muchos tipos de enteros, y también C ++. std::cout
maneja todos los tipos por usted, mientras que printf
requiere una sintaxis específica dependiendo de un tipo entero (hay tipos no enteros, pero el único tipo no entero que usará en la práctica con printf
es const char *
(cadena C, Puede obtenerse usando el método to_c
de std::string
)). Por ejemplo, para imprimir size_t
, necesita usar %zd
, mientras que int64_t
requerirá usar %"PRId64"
. Las tablas están disponibles en printf() y http://en.cppreference.com/w/cpp/types/integer .
No puede imprimir el byte NUL, /0
Como printf
usa cadenas C en lugar de cadenas C ++, no puede imprimir el byte NUL sin trucos específicos. En ciertos casos, es posible usar %c
con ''/0''
como argumento, aunque eso es claramente un hack.
Las diferencias que a nadie le importan.
Actuación
Actualización: Resulta que iostream
es tan lento que generalmente es más lento que su disco duro (si redirige su programa a un archivo). Desactivar 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
.
Todos piensan que les importa el rendimiento, pero nadie se molesta en medirlo. Mi respuesta es que I / O es un cuello de botella de todos modos, no importa si usa printf
o iostream
. Pienso que printf
podría ser más rápido con un vistazo rápido al ensamblaje (compilado con un sonido metálico usando la opción del compilador -O3
). Suponiendo que mi ejemplo de error, el ejemplo de printf
hace menos llamadas que el ejemplo cout
. 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 observar fácilmente que dos cadenas y 2
(número) se insertan como argumentos de printf
. Eso es todo; no hay nada más. Para comparación, esto es iostream
compilado para ensamblar. No, no hay en línea; cada 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 I / O es el cuello de botella de todos modos. Solo quería mostrar que iostream
no es más rápido porque es "de tipo seguro". La mayoría de las implementaciones de C implementan formatos de printf
usando goto computado, por lo que printf
es tan rápido como puede ser, incluso sin que el compilador tenga conocimiento de printf
(no es que no lo sean, algunos compiladores pueden optimizar printf
en ciertos casos, cadena constante que termina con /n
se suele optimizar para puts
).
Herencia
No sé por qué querría heredar ostream
, pero no me importa. Es posible con FILE
también.
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 de C populares pueden detectar problemas con la printf
formato printf
si habilitas las advertencias. De hecho, Clang puede hacer eso sin habilitar 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);
^
Para mí, las diferencias reales que me harían ir por ''cout'' en lugar de ''printf'' son:
1) << operador puede ser sobrecargado para mis clases.
2) La secuencia de salida para cout se puede cambiar fácilmente a un archivo: (: copiar 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 que el cout es más legible, especialmente cuando tenemos muchos parámetros.
Un problema con cout
es las opciones de formato. Formatear los datos (precisión, justificación, etc.) en printf
es más fácil.
Por supuesto, puedes 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 un poco de prueba extendida de cout vs. printf, agregó 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
Una es una función que imprime a la salida estándar. El otro es un objeto que proporciona varias funciones miembro y sobrecargas del operator<<
que imprimen a la salida estándar. Podría enumerar muchas más diferencias, pero no estoy seguro de lo que está buscando.
Y quote :
En términos de alto nivel, las principales diferencias son la seguridad de tipo (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 salida sin problemas de los tipos definidos por el usuario).
printf
Es una función mientras que cout
es una variable.
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 verificación de tipos, printf no lo hace.
No hay iostream equivalente de "% d"
No soy programador, pero he sido ingeniero de factores humanos. Creo que un lenguaje de programación debería ser fácil de aprender, entender 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 núcleo, arbitrarios, existen convenciones y seguirlas facilita el aprendizaje y el uso del idioma.
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 pre-computacional. printf()
sigue esta sintaxis y si los escritores de C ++ quisieran crear un método lógicamente diferente para leer y escribir archivos, simplemente podrían haber creado una función diferente utilizando una sintaxis similar.
En Python, por supuesto, podemos imprimir utilizando la object.method
sintaxis también bastante estándar , es decir, nombre de archivo variable, ya que las variables son objetos, pero en C ++ no lo son.
No me gusta la sintaxis de 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ático. Este es un enfoque pobre desde el punto de vista de los factores humanos.
TL; DR: Siempre realice su propia investigación, con respecto al tamaño del código de la máquina , el rendimiento , la legibilidad y el tiempo de codificación generados antes de confiar en los comentarios aleatorios en línea, incluido este.
No soy un experto. Acabo de escuchar a dos compañeros de trabajo que hablan sobre cómo deberíamos evitar el uso de C ++ en sistemas integrados debido a problemas de rendimiento. Bueno, lo suficientemente interesante, hice un punto de referencia basado en una tarea de proyecto real.
En dicha tarea, tuvimos que escribir alguna configuración en la memoria RAM. Algo como:
café =
azúcar caliente = ninguna
leche = mama
mac = AA: BB: CC: DD: EE: FF
Aquí están mis programas de referencia (Sí, sé que OP preguntó acerca de 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 de 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 lo mejor que pude para pulirlos antes de enlazarlos 100,000 veces. Aquí están los resultados:
Programa C:
real 0m 8.01s
user 0m 2.37s
sys 0m 5.58s
Programa de C ++:
real 0m 6.07s
user 0m 3.18s
sys 0m 2.84s
Tamaño del archivo objeto:
C - 2,092 bytes
C++ - 3,272 bytes
Conclusión: en mi plataforma muy específica , con un procesador muy específico , ejecutando una versión muy específica del kernel de Linux , para ejecutar un programa que se compila con una versión muy específica de GCC , para cumplir una tarea muy específica , diría El enfoque de C ++ es más adecuado porque se ejecuta significativamente más rápido y proporciona una mejor legibilidad. Por otro lado, C ofrece una huella pequeña, en mi opinión, significa casi nada porque el tamaño del programa no es de nuestra incumbencia.
Recuerda, YMMV.
cout<< "Hello";
printf("%s", "Hello");
Ambos se utilizan para imprimir valores. Tienen una sintaxis completamente diferente. C ++ tiene ambos, C solo tiene printf.