Sé que he oído con bastante frecuencia que C generalmente tiene una ventaja de rendimiento sobre C ++. Realmente no pensé en nada más hasta que me di cuenta de que MSVC ni siquiera parece admitir el estándar más nuevo de C, pero el más nuevo lo admite C99 (que yo sepa).
Estaba planeando escribir una biblioteca con algún código para renderizar en OpenGL para poder reutilizarla. Estaba planeando escribir la biblioteca en C ya que cualquier aumento de rendimiento es bienvenido cuando se trata de gráficos.
¿Pero realmente valdría la pena? El código que usa la biblioteca probablemente se escribiría en C ++ y prefiero codificar en C ++ en general.
Sin embargo, si produjera incluso una pequeña diferencia en el rendimiento, probablemente iría con C.
También cabe señalar que esta biblioteca sería algo que haría que funcione en Windows / OS X / Linux, y probablemente compile todo de forma nativa (MSVC para Windows, Clang o GCC para OS X, y GCC para Linux .. .o posiblemente los compiladores de Intel para todo).
He mirado a mi alrededor y he encontrado algunos puntos de referencia y demás, pero todo lo que he visto ha tratado con GCC en lugar de MSVC y Clang. Además, los puntos de referencia no mencionan los estándares de los idiomas utilizados. ¿Alguno tiene alguna idea sobre esto?
EDITAR:Solo quería compartir mi punto de vista sobre esta pregunta después de un par de años más de experiencia. Terminé escribiendo el proyecto por el que hacía esta pregunta en C ++. Comencé otro proyecto más o menos al mismo tiempo en C, ya que estábamos buscando obtener una pequeña cantidad de rendimiento que pudiéramos y necesitábamos que el proyecto pudiera vincularse en C. Hace un par de meses, llegué al punto en el que realmente necesitaba mapas y avancé. manipulación de cuerdas. Conocía las habilidades para esto en la biblioteca estándar de C ++ y finalmente llegué a la conclusión de que esas estructuras en la biblioteca estándar probablemente superarían y serían más estables que los mapas y cadenas que podría implementar en C en un período de tiempo razonable. El requisito de ser enlazable en C se cumplió fácilmente escribiendo una interfaz C en el código C ++, que se realizó rápidamente con tipos opacos. Reescribir la biblioteca en C ++ parecía ir mucho más rápido que cuando se escribía en C y era menos propenso a errores, especialmente a pérdidas de memoria. También pude usar la biblioteca de subprocesos de biblioteca estándar, que ha sido mucho más fácil que usar implementaciones específicas de la plataforma. Al final, creo que escribir la biblioteca en C ++ generó grandes beneficios, posiblemente con un pequeño costo de rendimiento. Todavía no he comparado la versión de C ++, pero creo que incluso es posible que haya ganado algo de rendimiento al usar estructuras de datos de biblioteca estándar que las que escribí. Creo que escribir la biblioteca en C ++ generó grandes beneficios, posiblemente con un pequeño costo de rendimiento. Todavía no he comparado la versión de C ++, pero creo que incluso es posible que haya ganado algo de rendimiento al usar estructuras de datos de biblioteca estándar que las que escribí. Creo que escribir la biblioteca en C ++ generó grandes beneficios, posiblemente con un pequeño costo de rendimiento. Todavía no he comparado la versión de C ++, pero creo que incluso es posible que haya ganado algo de rendimiento al usar estructuras de datos de biblioteca estándar que las que escribí.
Respuestas:
Supongo que las personas a menudo afirman que C es más rápido que C ++ porque es más fácil razonar sobre el rendimiento en C. C ++ no es inherentemente más lento o más rápido, pero cierto código de C ++ puede ocultar las sanciones ocultas de rendimiento. Por ejemplo, puede haber copias y conversiones implícitas que no son visibles de inmediato cuando se observa algún fragmento de código C ++.
Tomemos la siguiente declaración:
Supongamos además que
doSomething
tiene la siguiente firma:Ahora, tratemos de analizar el posible impacto en el rendimiento de esta declaración en particular.
En C, las implicaciones son bastante claras.
foo
solo puede ser un puntero a una estructura ydoSomething
debe ser un puntero a una función.*c
desreferencia un largo, ya + 5
es la suma entera. La única incertidumbre proviene del tipo dea
: Si no es un int, habrá alguna conversión. pero aparte de eso, es fácil cuantificar el impacto en el rendimiento de esta declaración única.Ahora pasemos a C ++. La misma declaración ahora puede tener características de rendimiento muy diferentes:
doSomething
podría ser una función miembro no virtual (barata), función miembro virtual (un poco más cara)std::function
, lambda ... etc. Lo que es peor,foo
podría ser una sobrecarga de tipo de claseoperator->
con alguna operación de complejidad desconocida. Entonces, para cuantificar el costo de llamardoSomething
, ahora es necesario conocer la naturaleza exacta defoo
ydoSomething
.a
podría ser un número entero, o una referencia a un número entero (indirección adicional), o un tipo de clase que implementaoperator+(int)
. El operador podría incluso devolver otro tipo de clase que es implícitamente convertible aint
. Nuevamente, el costo de rendimiento no es aparente solo en la declaración.c
podría ser un tipo de implementación de claseoperator*()
. También podría ser una referencia a unlong*
etc.Te dan la imagen. Debido a las características del lenguaje de C ++, es mucho más difícil cuantificar los costos de rendimiento de una sola declaración que en C. Ahora, además, abstracciones como
std::vector
,std::string
se usan comúnmente en C ++, que tienen sus propias características de rendimiento, y ocultan las asignaciones de memoria dinámica ( ver también la respuesta de @ Ian).Entonces, la conclusión es: en general, no hay diferencia en el rendimiento posible que se puede lograr usando C o C ++. Pero para un código realmente crítico para el rendimiento, las personas a menudo prefieren usar C porque hay menos penalizaciones de rendimiento ocultas posibles .
fuente
El código escrito en C ++ puede ser más rápido que en C, para ciertos tipos de tareas.
Si prefiere C ++, use C ++. Cualquier problema de rendimiento será insignificante en comparación con las decisiones algorítmicas de su software.
fuente
Uno de los principios de diseño de C ++ es que no paga por las funciones que no usa. Entonces, si escribe código en C ++ y evita características que no existen en C, entonces el código compilado resultante debería ser equivalente en rendimiento (aunque tendría que medir esto).
Hay un costo insignificante para usar clases, por ejemplo, en comparación con estructuras y un montón de funciones asociadas. Las funciones virtuales costarán un poco más, y tendría que medir el rendimiento para ver si es importante para su aplicación. Lo mismo ocurre con cualquier otra característica del lenguaje C ++.
fuente
this
función de lenguaje de puntero. Eso es todo lo que estaba diciendo.Una razón por la que los lenguajes de nivel superior a veces son más lentos es porque pueden ocultar mucho más administración de memoria que los idiomas de nivel inferior.
Cualquier lenguaje (o biblioteca, API, etc.) que abstraiga detalles de bajo nivel puede estar ocultando operaciones costosas. Por ejemplo, en algunos idiomas, simplemente recortar los espacios en blanco al final de una cadena da como resultado una asignación de memoria y una copia de la cadena. La asignación y copia de memoria en particular puede ser costosa si ocurren repetidamente en un ciclo cerrado.
Si escribieras este tipo de código en C, sería evidente. En C ++ posiblemente menos, porque las asignaciones y la copia podrían abstraerse en una clase en algún lugar. Incluso podrían estar ocultos detrás de un operador o constructor de copia sobrecargado de aspecto inocente.
Así que usa C ++ si quieres. Pero no se deje engañar por la aparente conveniencia de las abstracciones cuando no sabe qué hay debajo de ellas.
Por supuesto, use un generador de perfiles para descubrir qué es lo que realmente está ralentizando su código.
fuente
Por lo que vale, tiendo a escribir mis bibliotecas en C ++ 11 para el conjunto de características mejoradas. Me gusta poder aprovechar cosas como punteros compartidos, excepciones, programación genérica y otras características exclusivas de C ++. Me gusta C ++ 11 porque he descubierto que buena parte de él es compatible con todas las plataformas que me interesan. Visual Studio 2013 tiene mucho de las funciones principales del lenguaje e implementaciones de la biblioteca listas para funcionar y supuestamente está trabajando para agregar el resto. Como bien sabes, Clang y GCC también admiten todo el conjunto de características.
Dicho esto, recientemente leí acerca de una estrategia realmente excelente con respecto al desarrollo de la biblioteca que creo que es directamente relevante para su consulta. El artículo se titula "Estilo de manejo de errores de CA que funciona bien con las excepciones de C ++" Stefanu Du Toit se refiere a esta estrategia como un patrón de "reloj de arena". El primer párrafo del artículo:
Ahora para abordar su principal preocupación: el rendimiento.
Sugeriría, como muchas de las otras respuestas aquí, que escribir código en cualquier idioma funcionaría igual de bien desde el punto de vista del rendimiento. Desde un punto de vista personal, creo que escribir el código correcto en C ++ es más fácil debido a las características del lenguaje, pero creo que es una preferencia personal. De cualquier manera, los compiladores son realmente inteligentes y tienden a escribir mejor código que usted de todos modos. Es decir que el compilador probablemente optimizará su código mejor que usted.
Sé que muchos programadores dicen esto, pero lo primero que debes hacer es escribir tu código, luego perfilarlo y hacer optimizaciones donde tu perfilador te sugiera que lo hagas. Dedicará mucho más tiempo a producir funciones y luego a optimizarlas una vez que pueda ver dónde están sus cuellos de botella.
Ahora, para algunas lecturas divertidas sobre cómo las funciones y optimizaciones del lenguaje realmente pueden funcionar a su favor:
std :: unique_ptr tiene cero sobrecarga
constexp permite el cálculo en tiempo de compilación
mover semántica evita objetos temporales innecesarios
fuente
std::unique_ptr has zero overhead
Esto no puede ser cierto (técnicamente hablando) porque tiene que llamar a su constructor si la pila se desenrolla debido a una excepción. Un puntero sin formato no tiene esta sobrecarga y sigue siendo correcto si su código probablemente no se lanzará. Un compilador no podrá probar esto en el caso general.unique_ptr
? Está declaradonoexcept
, y por lo menos maneja todas las excepciones, pero no puedo imaginar qué tipo de excepción podría lanzarse en primer lugar.La diferencia de rendimiento entre C ++ y C no se debe a nada en el lenguaje, estrictamente hablando, sino a lo que te tienta a hacer. Es como una tarjeta de crédito frente a efectivo. No te hace gastar más, pero lo haces de todos modos, a menos que seas muy disciplinado.
Aquí hay un ejemplo de un programa escrito en C ++, que luego se ajustó agresivamente. Debe saber cómo realizar ajustes de rendimiento agresivos, independientemente del idioma. El método que uso es una pausa aleatoria, como se muestra en este video .
Los tipos de cosas costosas que C ++ te tienta a hacer son la administración excesiva de memoria, la programación de estilo de notificación, confiar el contador de su programa en bibliotecas de abstracción de varias capas (como dijo @Ian), ocultar la lentitud, etc.
fuente
C no tiene ninguna ventaja de rendimiento en comparación con C ++ si hace lo mismo en ambos lenguajes. Puede tomar cualquier código C antiguo escrito por cualquier programador C decente y convertirlo en código C ++ válido y equivalente, que se ejecutará igual de rápido (a menos que tanto usted como su compilador sepan qué hace la palabra clave "restringir" y la usen de manera efectiva, pero la mayoría de la gente no)
C ++ puede tener un rendimiento muy diferente, más lento o más rápido, si (1) usa la biblioteca estándar de C ++ para hacer cosas que se pueden hacer mucho más rápido y más fácil sin usar la biblioteca, o (2) si usa la biblioteca estándar de C ++ hacer las cosas mucho más fácil y más rápido que reimplementando la biblioteca en C.
fuente