2011-03-16 19 views
22

Estaba codificando C++ para un pequeño proyecto de hobby cuando noté que estoy usando operaciones de estilo C para acceder a IO (printf, fopen, etc.).C++ Streams vs. C-style IO?

¿Se considera una "mala práctica" involucrar funciones C en proyectos C++? ¿Cuáles son las ventajas de usar flujos sobre el acceso I/O estilo C?

Respuesta

38

Esta es una climatizada tema.

Algunas personas prefieren usar el C++ IO ya que son seguros para el tipo (no puede haber divergencia entre el tipo del objeto y el tipo especificado en el formato de cadena), y fluyen más naturalmente con el resto del C++ forma de codificación.

Sin embargo, también hay argumentos para las funciones C IO (mis favoritos personales). Algunos de ellos son:

  • Se integran más fácilmente con la localización, como a toda la cadena de localizar no se rompe en cadenas más pequeñas, y con un poco de aplicación del localizador pueden reordenar el orden del valor insertado, moverlos en la cadena, ...
  • Puede ver directamente el formato del texto que se escribirá (esto puede ser realmente difícil con los operadores de flujo).
  • Como no hay alineación, y solo una instancia de la función printf, el código generado es más pequeño (esto puede ser importante en el entorno integrado).
  • Más rápido que la función C++ en alguna implementación.

Personalmente, no consideraría una mala práctica usar C stream en código C++. Some organisations incluso recomiendo usarlos sobre flujo de C++. Lo que consideraría un estilo malo es usar ambos en el mismo proyecto. La consistencia es la clave aquí, creo.


Como otros han señalado, en una proporción relativamente grande de proyectos, es probable que no los utilizan directamente, sino que se utilizaría un conjunto de función de contenedor (o clases), que se acomoda mejor a su estándar de codificación, y su necesidades (localización, tipo de seguridad, ...). Puede utilizar una u otra interfaz IO para implementar esta interfaz de nivel superior, pero probablemente solo use una.


Editar: la adición de alguna información acerca de la ventaja de la familia función printf formato relacionados con la localización. Tenga en cuenta que esa información solo es válida para alguna implementación.

Puede usar %m$ en lugar de % para referenciar el parámetro por índice en lugar de hacer referencia a ellos secuencialmente. Esto se puede usar para reordenar valores en la cadena formateada. El siguiente programa escribirá Hello World! en la salida estándar.

#include <stdio.h> 
int main() { 
    printf("%2$s %1$s\n", "World!", "Hello"); 
    return 0; 
} 

posibilidad de traducir este código C++:

if (nb_files_deleted == 1) 
    stream << "One file "; 
else 
    stream << nb_file_deleted << " files "; 
stream << removed from directory \"" << directory << "\"\n"; 

Esto puede ser muy difícil. Con printf (y una biblioteca como gettext para manejar la localización), el código no se mezcla con la cadena. Así podemos pasar la cadena al equipo de localización, y no tendremos que actualizar el código si hay un caso especial en algún idioma (en algún idioma, si el conteo del objeto es 0, usted usa una forma plural, en otro idioma, hay tres formas, una para singular, una cuando hay dos objetos y una forma plural, ...).

printf (ngettext ("One file removed from directory \"%2$s\"", 
        "%1$d files removed from directory \"%2$s\"", 
        n), 
     n, dir); 
+2

+1 para la viñeta de localización. Pero, ¿cómo reordenar los valores en printf? –

+2

He actualizado mi publicación para explicar cómo puede reordenar los valores en 'printf' (sugerencia:'% m $ '). –

+0

Gracias por la actualización. Si pudiera, podría volver a votar nuevamente. –

3

Para empezar, no tiene que convertir objetos C++ (notablemente string s) a formularios compatibles con C primero.

+1

Sí, me estoy cansando de tener que escribir 'str.c_str()' todo el tiempo ... – gablin

3

En mi humilde opinión, un verdadero programador de C++ intenta hacer las cosas de manera idiomática en C++; el programador convertido C intenta aferrarse a las viejas formas de hacer las cosas. Tiene que ver con la legibilidad y la coherencia.

+16

Un programador pragmático usa la mejor herramienta disponible ... – PeterSW

5

No se puede considerar una mala práctica si tiene un propósito definido. Quiero decir, si IO es el cuello de botella del programa, entonces sí, IO estilo C funciona más rápido que C++ IO. Pero si no es así, iría con el enfoque de transmisión C++. Porque es más lindo :)

6

Para un proyecto de hobby pequeño, probablemente iría con las corrientes de C++ io más seguras.

Bastante curioso, nunca he visto un proyecto de la vida real no trivial que utilice cualquiera de ellos. En todos los casos, utilizamos algunas abstracciones construidas sobre la API del sistema operativo nativo para IO.

7

printf y los amigos son terriblemente insegura en comparación con <iostream>, y no pueden extenderse, además, por supuesto fopen y amigos no tienen RAII, lo que significa que a menos que has demostrado con un generador de perfiles que usted necesita definitivamente la diferencia de rendimiento (que se 'demostrado que existe en su plataforma y en su código), usted tendría que ser un idiota al printf.

Editar: La localización es algo interesante que no había considerado. Nunca he localizada cualquier código y no puedo comentar sobre la capacidad relativa de localizational printf y <iostream>

+3

AFAIK, la localización básica se hace extrayendo los literales de cadena del programa (que están rodeados por una llamada a una función de traducción) y que las personas traduzcan esas cadenas. Imagine tener que traducir y construir oraciones con sentido a partir de los fragmentos de oraciones que obtiene con cout. - Boost.Format puede ayudarte con esto, sin embargo. – UncleBens

3

¿Se considera "mala práctica" para involucrar a las funciones de C en proyectos de C++?

Por lo general, el código IO archivo debe ser encapsulado en una implementación de la clase o función. No consideraría que las elecciones que realice en las implementaciones encapsuladas sean "malas prácticas", reservo ese término para lo que afecta al usuario de su biblioteca o código (es decir, la interfaz). Si está exponiendo su mecanismo IO de archivos en la interfaz, entonces, IMO, es una mala práctica si usa IO stream o C-style IO functions.

Preferiría decir que las funciones IO de estilo C son (probablemente siempre) la peor opción.

¿Cuáles son las ventajas de utilizar las corrientes más al estilo de C acceso IO?

En primer lugar, se integran mejor con C++ estándar construye como std::string. Se integran bastante bien con STL <algorithms>. Y le permiten crear operadores de lectura/escritura personalizados encapsulados (< < y >>) de modo que sus clases personalizadas casi parezcan tipos primitivos cuando se trata de realizar operaciones IO.

Finalmente, las secuencias de IO en C++ pueden usar un mecanismo de excepción para informar errores en las operaciones de transmisión o de lectura/escritura. Esto hace que el código IO del archivo sea mucho más agradable al evitar el terrible aspecto de los mecanismos de código de error (secuencia de sentencias if y feos ciclos while, que verifican el código de error después de cada operación).

+0

En ese caso no necesito preocuparme, ya que encapsular el código IO en una clase es exactamente lo que he hecho. =) – gablin

3

Como regla general, se debe preferir los operadores de C++, que son:

- Tipo segura. No se arriesga a pasar un doble donde el formato requiere un int.

- Extensible. Puede escribir sus propios insertadores y extractores , y usarlos.

- Extensible. Puede definir sus propios manipuladores (con el significado lógico específico de la aplicación ) y usarlos. Si desea cambiar el formato de todo el WidgitNumber (internamente, un int) en su salida, cambie el manipulador ; no tiene que encontrar todas las declaraciones de formato donde% d es un WidgitNumber.

- Extensible. Puede escribir sus propios receptores y fuentes, y estos pueden enviarse a otros receptores y fuentes, filtrando o expandiendo la entrada o la salida como desee.

(Fwiw: No creo que he escrito una aplicación que no utilizó personalizada >> y < < operadores, manipuladores personalizados, y personalizados de streambuf.)

5

Ventajas

  • de seguridad Tipo: los tipos de argumentos de C++ operaciones de streaming se comprueban en tiempo de compilación, mientras que printf argumentos se pasan a través ... causando un comportamiento indefinido si no coinciden con el formato.
  • Administración de recursos: los objetos de flujo C++ tienen destructores para cerrar manejadores de archivos, búferes libres y lo que usted tiene. Las transmisiones en C requieren que recuerde llamar al fclose.

Desventajas

  • Rendimiento: esto depende de la aplicación, por supuesto, pero he encontrado el formato con corrientes de C++ para ser considerablemente más lento que el formato equivalente printf.
2

¿Se considera una "mala práctica" involucrar funciones C en proyectos C++?

Las funciones de No. C a menudo se usan en proyectos de C++. Con respecto a las transmisiones, Google C++ Style Guide, por ejemplo, recomienda usarlas solo en casos limitados, como "ad-hoc, local, legible para personas y dirigido a otros desarrolladores en lugar de a usuarios finales".

¿Cuáles son las ventajas de usar flujos sobre el acceso I/O estilo C?

Las principales ventajas son la seguridad y extensibilidad. Sin embargo, las transmisiones en C++ tienen fallas graves, ver the answers to this question tales como problemas con la localización, informes de errores deficientes, problemas de rendimiento de código en algunas implementaciones.

+0

En realidad, no es cierto que la Guía de estilo de Google C++, por ejemplo, recomiende usar E/S estilo C sobre E/S estilo C++. Dice que es mejor usar bibliotecas alternativas para usos más complejos, pero de lo contrario use las transmisiones cuando sea necesario. Ni siquiera menciona el sistema C I/O – Triskeldeian

+0

Debieron haber cambiado eso. He actualizado la respuesta, ¡gracias! – vitaut