una tipos the standard para librerias library lenguaje funciones fuente español dev definicion crear codigo clases bibliotecas biblioteca basicas c++ c performance c-libraries

tipos - ¿Existe una degradación/penalización del rendimiento en el uso de una biblioteca C pura en código C++?



the standard c library pdf español (3)

C ++ ha crecido y cambiado mucho desde su inicio, pero por diseño es compatible con versiones anteriores de C. Los compiladores de C ++ generalmente se construyen a partir de compiladores de C, pero aún más se modernizan con optimizaciones de tiempo de enlace . Me imagino que una gran cantidad de software puede mezclar confiablemente el código C y C ++, tanto en los espacios de usuario como en las bibliotecas utilizadas. Respondí recientemente a una pregunta que involucraba pasar un puntero a la función miembro de la clase C ++ a una función de biblioteca implementada por C. El cartel decía que funcionaba para él. Por lo tanto, es posible que C ++ sea más compatible con C de lo que cualquier programador o usuario pueda pensar.

Sin embargo, C ++ funciona en muchos paradigmas diferentes que C no, ya que está orientado a objetos, e implementa todo un espectro de abstracciones, nuevos tipos de datos y operadores. Ciertos tipos de datos son fácilmente traducibles (cadena char * C a std::string ), mientras que otros no lo son. Esta sección en GNU.org sobre las opciones del compilador de C ++ puede ser de algún interés.

Al mezclar los dos idiomas, no estaría demasiado preocupado ni preocupado por una disminución en el rendimiento. El usuario final, e incluso el programador, apenas notarán cambios medibles en el rendimiento, a menos que traten con grandes abstracciones de datos.

Vi este enlace pero no estoy pidiendo una degradación del rendimiento para el código usando "extern". Quiero decir sin "extern", ¿hay "cambio de contexto" cuando se usa la biblioteca C en C ++? ¿Hay algún problema al usar funciones C puras (no envueltas en clase) en la aplicación C ++?


En un nivel básico, no , no verá ningún tipo de penalización de rendimiento de "cambio" al llamar a una biblioteca C desde el código C ++. Por ejemplo, llamar desde C ++ a un método de C definido en otra unidad de traducción debe tener un rendimiento aproximadamente idéntico al de llamar al mismo método implementado en C ++ (de la misma forma en que C) en otra unidad de traducción.

Esto se debe a que las implementaciones comunes de los compiladores de C y C ++ finalmente compilan el código fuente en código nativo, y la función de extern "C" se admite de manera eficiente utilizando el mismo tipo de call que puede ocurrir para una llamada de C ++. Las convenciones de llamada generalmente se basan en la plataforma ABI y son similares en ambos casos.

Dejando de lado este hecho básico, es posible que todavía haya algunos inconvenientes en el rendimiento al llamar a una función C en lugar de implementar la misma función en C ++:

  • Las funciones implementadas en C y declaradas como extern "C" y llamadas desde código C ++ generalmente no estarán en línea (ya que, por definición, no están implementadas en un encabezado), lo que inhibe toda una gran cantidad de optimizaciones posiblemente muy potentes.
  • La mayoría de los tipos de datos utilizados en el código C ++ 1 no pueden ser utilizados directamente por el código C, por lo que, por ejemplo, si tiene una std::string en su código C ++, deberá elegir un tipo diferente para pasarlo al código C: char * es común pero pierde información sobre la longitud explícita, que puede ser más lenta que una solución de C ++. Muchos tipos no tienen un equivalente directo de C, por lo que es posible que tenga que realizar una conversión costosa.
  • El código C usa malloc y free para la gestión dinámica de la memoria, mientras que el código C ++ generalmente usa new y delete (y generalmente prefiere ocultar esas llamadas detrás de otras clases tanto como sea posible). Si necesita asignar memoria en un idioma que se liberará en otro, esto puede causar una discrepancia en el que necesita volver a llamar al "otro" idioma para hacer las copias gratuitas o innecesarias, etc.
  • El código C a menudo hace un uso intensivo de las rutinas de la biblioteca estándar de C, mientras que el código C ++ generalmente utiliza métodos de la biblioteca estándar de C ++. Dado que hay una gran cantidad de superposición funcional, es posible que una combinación de C y C ++ tenga una huella de código mayor que la del código C ++ puro, ya que se utilizan más métodos de biblioteca C 2 .

Las preocupaciones anteriores solo se aplicarían al contrastar una implementación pura de C ++ frente a una C uno, y no significa que haya una degradación del rendimiento al llamar a C: realmente está respondiendo a la pregunta "¿Por qué escribir una aplicación en una combinación de C y ¿C ++ será más lento que el puro C ++? ". Además, los problemas anteriores son principalmente una preocupación para llamadas muy cortas en las que los gastos generales anteriores pueden ser significativos. Si está llamando una función larga en C, es un problema menor. La "falta de coincidencia de tipo de datos" podría seguir mordiéndote, pero esto puede diseñarse alrededor del lado de C ++.

0 Curiosamente, la optimización del tiempo de enlace en realidad permite que los métodos de C se incluyan en el código C ++ , lo que es un beneficio poco mencionado de LTO. Por supuesto, esto generalmente depende de la construcción de la biblioteca de C desde la fuente con las opciones de LTO apropiadas.

1 Por ejemplo, casi cualquier cosa que no sea un tipo de diseño estándar.

2 Esto se ve al menos parcialmente mitigado por el hecho de que muchas llamadas de la biblioteca estándar de C ++ finalmente delegan a las rutinas de la biblioteca C para el levantamiento "pesado", como la forma en que std::copy llama a memcpy o memset cuando es posible y cómo la mayoría de las new implementaciones llaman a malloc .


Tanto C como C ++ son especificaciones de lenguaje de programación (escritas en inglés, ver, por ejemplo, n1570 para la especificación de C11) y no hablan sobre el rendimiento (sino sobre el comportamiento del programa, es decir, sobre la semantics ).

Sin embargo, es probable que use un compilador como GCC o Clang que no conlleva ninguna penalización de rendimiento, ya que genera el mismo tipo de representación interna intermedia (por ejemplo, GIMPLE para GCC y LLVM para Clang) para los lenguajes C y C ++. y porque los códigos C y C ++ utilizan ABI y convenciones de llamada compatibles.

En la práctica, la extern "C" no cambia ninguna convención de llamada, pero desactiva la manipulación de nombres . Sin embargo, su influencia exacta en el compilador es específica de ese compilador. Puede (o no) deshabilitar el inlining (pero considere -flto para la optimización de tiempo de enlace en GCC).

Algunos compiladores de C (por ejemplo, tinycc ) producen código con bajo rendimiento. Incluso GCC o Clang , cuando se usan con -O0 o sin habilitar explícitamente la optimization (por ejemplo, al passing -O1 o -O2 etc.) pueden producir código lento (y las optimizaciones están deshabilitadas de forma predeterminada).

Por cierto, C ++ fue diseñado para ser interoperable con C (y esa fuerte restricción explica la mayoría de las deficiencias de C ++).

En algunos casos, el código C ++ genuino puede ser un poco más rápido que el código C genuino correspondiente. Por ejemplo, para ordenar una matriz de números, usará std::array y std::sort en C ++ genuino, y es probable que las operaciones de comparación en la clasificación estén en línea. Con el código C, solo usará qsort y cada comparación pasa por una llamada de función indirecta (porque el compilador no está incorporando qsort , incluso si en teoría podría ...).

En algunos otros casos, el código genuino de C ++ podría ser un poco más lento; por ejemplo, varias implementaciones (pero no todas) de ::operator new simplemente están llamando a malloc (luego verificando el fallo) pero no están en línea.

En la práctica, no hay ninguna penalización al llamar al código C desde el código C ++ o al código C ++ desde el código C, ya que las convenciones de llamada son compatibles.

La instalación de C longjmp es probablemente más rápida que lanzar excepciones de C ++, pero no tienen la misma semántica (ver desenrollado de la pila ) y longjmp no se mezcla bien con el código de C ++.

Si le importa mucho el rendimiento, escriba (en C original y en C ++ original) el doble de su código y punto de referencia. Es probable que observe un pequeño cambio (unos pocos porcentajes como máximo) entre C y C ++, por lo que no me molestaría en absoluto (y sus problemas de rendimiento son prácticamente injustificados).

El cambio de contexto es un concepto relacionado con el sistema operativo y la multitasking y ocurre en los processes ejecutan el código de máquina ejecutable durante la preemption . La forma en que se obtiene ese executable (de un compilador de C, de un compilador de C ++, de un compilador de Go, de un compilador de SBCL o de ser un intérprete de algún otro lenguaje como Perl o bytecode Python) es totalmente irrelevante (ya que puede ocurrir un cambio de contexto En cualquier instrucción de la máquina , durante las interrupts ). Lee algunos libros como Sistemas Operativos: Tres Piezas Eeasy .