Estoy usando mucho printf
para fines de rastreo / registro en mi código, descubrí que es una fuente de error de programación. Siempre encontré que el operador de inserción ( <<
) es algo extraño, pero estoy empezando a pensar que al usarlo podría evitar algunos de estos errores.
¿Alguien alguna vez tuvo una revelación similar o solo estoy agarrando pajillas aquí?
Algunos quitan puntos
- Mi línea de pensamiento actual es que la seguridad de tipografía supera cualquier beneficio de usar printf. El verdadero problema es la cadena de formato y el uso de funciones variadas que no son de tipo seguro.
- Tal vez no
<<
usaré las variantes de flujo de salida stl, pero ciertamente buscaré usar un mecanismo de tipo seguro que sea muy similar. - Gran parte del rastreo / registro es condicional, pero me gustaría ejecutar siempre el código para no perder errores en las pruebas solo porque es una rama raramente tomada.
printf
en el mundo de C ++? Me estoy perdiendo algo aquí?printf
en C ++. (Si es una buena idea es otra pregunta).printf
tiene algunas ventajas; mira mi respuestaRespuestas:
printf, particularmente en los casos en los que podría interesarle el rendimiento (como sprintf y fprintf) es un truco realmente extraño. Constantemente me sorprende que las personas que trabajan con C ++ debido a una sobrecarga de rendimiento minúsculo relacionada con las funciones virtuales continúen defendiendo el io de C.
Sí, para descubrir el formato de nuestra salida, algo que podemos saber al 100% en el momento de la compilación, analicemos una cadena de formato en el tiempo de ejecución dentro de una tabla de salto masivamente extraña usando códigos de formato inescrutables.
Por supuesto, estos códigos de formato no se pueden hacer para que coincidan con los tipos que representan, eso sería demasiado fácil ... y cada vez que se busca se le recuerda si es% llg o% lg que este lenguaje (fuertemente tipado) lo hace descifre los tipos manualmente para imprimir / escanear algo, Y fue diseñado para procesadores anteriores a 32 bits.
Admito que el manejo del ancho y la precisión del formato de C ++ es voluminoso y podría usar algo de azúcar sintáctico, pero eso no significa que tenga que defender el extraño truco que es el principal sistema io de C. Los conceptos básicos absolutos son bastante fáciles en cualquier idioma (aunque probablemente debería estar usando algo como una función de error personalizada / flujo de error para el código de depuración de todos modos), los casos moderados son como expresiones regulares en C (fácil de escribir, difícil de analizar / depurar) ), y los casos complejos imposibles en C.
(Si utiliza los contenedores estándar, escriba algunas sobrecargas rápidas del operador con plantilla << que le permitan hacer cosas como la
std::cout << my_list << "\n";
depuración, donde my_list es de tipolist<vector<pair<int,string> > >
).fuente
operator<<(ostream&, T)
llamando ... buenosprintf
,! El rendimiento desprintf
no es óptimo, pero debido a esto, el rendimiento de iostreams es generalmente aún peor.Mezclar salidas de estilo C
printf()
(oputs()
oputchar()
o ...) constd::cout << ...
salidas de estilo C ++ puede no ser seguro. Si recuerdo correctamente, pueden tener mecanismos de almacenamiento en búfer separados, por lo que la salida podría no aparecer en el orden previsto. (Como AProgrammer menciona en un comentario,sync_with_stdio
aborda esto).printf()
es fundamentalmente de tipo inseguro. El tipo esperado para un argumento está determinado por la cadena de formato ("%d"
requiere unint
o algo que promuevaint
,"%s"
requiere unchar*
que debe apuntar a una cadena de estilo C terminada correctamente, etc.), pero pasar el tipo de argumento incorrecto da como resultado un comportamiento indefinido , no es un error diagnosticable. Algunos compiladores, como gcc, hacen un trabajo razonablemente bueno de advertencia sobre las discrepancias de tipo, pero solo pueden hacerlo si la cadena de formato es literal o se conoce de otro modo en el momento de la compilación (que es el caso más común), y tal el idioma no requiere advertencias. Si pasa el tipo de argumento incorrecto, pueden suceder cosas arbitrariamente malas.El flujo de E / S de C ++, por otro lado, es mucho más seguro, ya que el
<<
operador está sobrecargado para muchos tipos diferentes.std::cout << x
no tiene que especificar el tipo dex
; el compilador generará el código correcto para cualquier tipo quex
tenga.Por otro lado,
printf
las opciones de formato de IMHO son mucho más convenientes. Si quiero imprimir un valor de punto flotante con 3 dígitos después del punto decimal, puedo usarlo"%.3f"
, y no tiene ningún efecto en otros argumentos, incluso dentro de la mismaprintf
llamada. C ++setprecision
, por otro lado, afecta el estado de la secuencia y puede estropear la salida posterior si no tiene mucho cuidado de restaurar la secuencia a su estado anterior. (Este es mi motivo personal favorito; si me falta alguna forma limpia de evitarlo, comente).Ambos tienen ventajas y desventajas. La disponibilidad de
printf
es particularmente útil si tiene un fondo C y está más familiarizado con él, o si está importando código fuente C en un programa C ++.std::cout << ...
es más idiomático para C ++, y no requiere tanto cuidado para evitar desajustes de tipo. Ambos son C ++ válidos (el estándar C ++ incluye la mayoría de la biblioteca estándar C por referencia).Es probablemente la mejor manera de utilizar
std::cout << ...
por el bien de otros programadores de C ++ que pueden trabajar en su código, pero se puede utilizar cualquiera de ellos - en especial en el código de seguimiento que se va a tirar a la basura.Y, por supuesto, vale la pena pasar un tiempo aprendiendo cómo usar depuradores (pero eso podría no ser factible en algunos entornos).
fuente
printf
.std::ios_base::sync_with_stdio
.std::cout
utiliza una llamada separada para cada elemento que se imprime? Podría solucionarlo mediante la recopilación de una línea de salida en una cadena antes de imprimirla. Y, por supuesto, también puede imprimir un elemento a la vez conprintf
; es más conveniente imprimir una línea (o más) en una llamada.Lo más probable es que su problema provenga de la combinación de dos gestores de salida estándar muy diferentes, cada uno de los cuales tiene su propia agenda para ese pobre STDOUT. No obtiene garantías acerca de cómo se implementan, y es perfectamente posible que establezcan opciones de descriptor de archivo en conflicto, ambos intentan hacer cosas diferentes, etc. Además, los operadores de inserción tienen una ventaja importante
printf
:printf
le permitirá hacer esto:Mientras
<<
que no lo hará.Nota: Para la depuración, no usa
printf
ocout
. Usasfprintf(stderr, ...)
ycerr
.fuente
printf
no es de tipo seguro y mi línea de pensamiento actual es que la seguridad de tipo supera cualquier beneficio de usarprintf
. El problema es realmente la cadena de formato y la función variadic no segura de tipo.SomeObject
pasa si no es un puntero? Obtendrá datos binarios arbitrarios que el compilador decide representarSomeObject
.Hay muchos grupos, por ejemplo google, a los que no les gustan las transmisiones.
http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Streams
(Abre el triángulo para que puedas ver la discusión). Creo que la guía de estilo de google C ++ tiene MUCHOS consejos muy sensatos.
Creo que la compensación es que las transmisiones son más seguras, pero printf es más claro de leer (y más fácil de obtener exactamente el formato que desea).
fuente
printf
puede causar errores debido a la falta de seguridad de tipo. Hay algunas formas de abordar que, sin cambiar aiostream
's<<
operador y más complicado el formato:printf
cadenas de formato con losprintf
argumentos y pueden mostrar advertencias como las siguientes si no coinciden.printf
llamadas de estilo para que sean seguras.printf
cadenas de formato similares (Boost.Format, en particular, son casi idénticas aprintf
) manteniendoiostreams
la seguridad de tipo y la extensibilidad de tipo.fuente
La sintaxis de Printf es básicamente buena, menos algunos de tipeo oscuro. Si crees que está mal, ¿por qué C #, Python y otros lenguajes usan una construcción muy similar? El problema en C o C ++: no es parte de un lenguaje y, por lo tanto, el compilador no verifica la sintaxis correcta (*) y no se descompone en una serie de llamadas nativas si se optimiza la velocidad. Tenga en cuenta que si optimiza el tamaño, ¡las llamadas printf podrían resultar más eficientes! La sintaxis de transmisión de C ++ no es buena en mi humilde opinión. Funciona, la seguridad de tipos está ahí, pero la sintaxis detallada ... bleh. Quiero decir que lo uso, pero sin alegría.
(*) algunos compiladores HACEN esta comprobación además de casi todas las herramientas de análisis estático (uso Lint y nunca tuve ningún problema con printf desde entonces).
fuente
format("fmt") % arg1 % arg2 ...;
) con la seguridad de tipos. A costa de un mayor rendimiento, ya que genera llamadas de secuencia de cadena que generan internamente llamadas sprintf en muchas implementaciones.printf
es, en mi opinión, una herramienta de salida mucho más flexible para tratar con variables que cualquiera de las salidas de flujo de CPP. Por ejemplo:Sin embargo, es posible que desee utilizar el
<<
operador CPP cuando lo sobrecarga para un método en particular ... por ejemplo, para obtener un volcado de un objeto que contiene los datos de una persona en particular,PersonData
...Para eso, sería mucho más efectivo decir (suponiendo que
a
sea un objeto de PersonData)que:
El primero está mucho más en línea con el principio de encapsulación (No es necesario conocer los detalles, las variables de miembros privados), y también es más fácil de leer.
fuente
Se supone que no debes usar
printf
en C ++. Siempre. La razón es, como notó correctamente, que es una fuente de errores y el hecho de que imprimir tipos personalizados, y en C ++ casi todo debería ser tipos personalizados, es doloroso. La solución de C ++ son las corrientes.Sin embargo, hay un problema crítico que hace que las transmisiones no sean adecuadas para ninguna salida visible para el usuario El problema son las traducciones. Un ejemplo de préstamo del manual gettext dice que quieres escribir:
Ahora viene el traductor al alemán y dice: Ok, en alemán, el mensaje debería ser
Y ahora estás en problemas, porque él necesita mezclar las piezas. Hay que decir que incluso muchas implementaciones
printf
tienen problemas con esto. A menos que admitan la extensión para que pueda usarLos Boost.Format compatible con los formatos de estilo printf y tiene esta característica. Entonces escribes:
Desafortunadamente, conlleva un poco de penalización de rendimiento, porque internamente crea un flujo de cadena y utiliza el
<<
operador para formatear cada bit y, en muchas implementaciones, el<<
operador llama internamentesprintf
. Sospecho que sería posible una implementación más eficiente si realmente se desea.fuente
Está haciendo un gran trabajo inútil, además del hecho de que
stl
sea malo o no, depure su código con una serie deprintf
solo agregar 1 nivel más de posibles fallas.Simplemente use un depurador y lea algo sobre Excepciones y cómo atraparlas y lanzarlas; trate de no ser más detallado de lo que realmente necesita ser.
PD
printf
se usa en C, para el C ++ que tienesstd::cout
fuente