sirve que personalizados para origen leer gratis generador funciona cómo código cuál como codigos codigo code c++ optimization inline-functions tradeoff

c++ - personalizados - para que sirve el codigo qr en whatsapp



¿Por qué debería usar código en línea alguna vez? (16)

  • ¿Hay una gran diferencia entre el código "normal" y el código en línea?

Si y no. No, porque una función o método en línea tiene exactamente las mismas características que uno normal, el más importante es que ambos son seguros. Y sí, porque el código ensamblador generado por el compilador será diferente; con una función regular, cada llamada se traducirá en varios pasos: presionar parámetros en la pila, dar el salto a la función, abrir los parámetros, etc., mientras que una llamada a una función en línea será reemplazada por su código real, como un macro.

  • ¿El código en línea es simplemente una "forma" de macros?

¡ No ! Una macro es la sustitución de texto simple, que puede conducir a errores graves. Considera el siguiente código:

#define unsafe(i) ( (i) >= 0 ? (i) : -(i) ) [...] unsafe(x++); // x is incremented twice! unsafe(f()); // f() is called twice! [...]

Al usar una función en línea, está seguro de que los parámetros se evaluarán antes de que la función realmente se realice. También serán revisados ​​por tipo, y eventualmente convertidos para que coincidan con los tipos de parámetros formales.

  • ¿Qué tipo de compensación debe hacerse al elegir alinear su código?

Normalmente, la ejecución del programa debe ser más rápida cuando se usan funciones en línea, pero con un código binario más grande. Para obtener más información, debe leer GoTW#33 .

Soy desarrollador de C / C ++, y aquí hay un par de preguntas que siempre me desconcertaban.

  • ¿Hay una gran diferencia entre el código "normal" y el código en línea?
  • ¿Cuál es la principal diferencia?
  • ¿El código en línea es simplemente una "forma" de macros?
  • ¿Qué tipo de compensación debe hacerse al elegir alinear su código?

Gracias


Actuación

Como se ha sugerido en las respuestas anteriores, el uso de la palabra clave en inline puede hacer que el código sea más rápido mediante llamadas a funciones en línea, a menudo a expensas de mayores ejecutables. "Llamar llamadas de función" solo significa sustituir la llamada a la función objetivo con el código real de la función, después de completar los argumentos en consecuencia.

Sin embargo, los compiladores modernos son muy buenos para alinear las llamadas de función automáticamente sin que el usuario lo solicite cuando se configura una alta optimización. En realidad, los compiladores suelen ser mejores para determinar qué llamadas a en línea para aumentar la velocidad que los humanos.

Declarar funciones en inline explícitamente por el bien de la ganancia de rendimiento es (¿casi?) Siempre innecesario.

Además, los compiladores pueden ignorar la solicitud en inline si les conviene. Los compiladores harán esto si una llamada a la función es imposible de alinear (es decir, usando recursivos no triviales o indicadores de función) pero también si la función es simplemente demasiado grande para una ganancia de rendimiento significativa.

Una regla de definición

Sin embargo, declarar una función en línea usando la palabra clave en inline tiene otros efectos , y en realidad puede ser necesario para satisfacer la Regla de definición única (ODR): esta regla en el estándar C ++ establece que un símbolo dado puede declararse varias veces pero solo puede definirse una vez. Si el editor de enlaces (= vinculador) encuentra varias definiciones de símbolos idénticos, generará un error.

Una solución a este problema es asegurarse de que una unidad de compilación no exporte un símbolo dado dándole un enlace interno declarándolo static .

Sin embargo, a menudo es mejor marcar una función en inline . Esto le dice al vinculador que combine todas las definiciones de esta función a través de las unidades de compilación en una definición, con una dirección, y funciones compartidas-variables estáticas.

Como ejemplo, considere el siguiente programa:

// header.hpp #ifndef HEADER_HPP #define HEADER_HPP #include <cmath> #include <numeric> #include <vector> using vec = std::vector<double>; /*inline*/ double mean(vec const& sample) { return std::accumulate(begin(sample), end(sample), 0.0) / sample.size(); } #endif // !defined(HEADER_HPP)

// test.cpp #include "header.hpp" #include <iostream> #include <iomanip> void print_mean(vec const& sample) { std::cout << "Sample with x̂ = " << mean(sample) << ''/n''; }

// main.cpp #include "header.hpp" void print_mean(vec const&); // Forward declaration. int main() { vec x{4, 3, 5, 4, 5, 5, 6, 3, 8, 6, 8, 3, 1, 7}; print_mean(x); }

Tenga en cuenta que ambos archivos .cpp incluyen el archivo de encabezado y, por lo tanto, la definición de la función de la mean . Aunque el archivo se guarda con resguardos incluidos contra inclusión doble, esto dará como resultado dos definiciones de la misma función, aunque en diferentes unidades de compilación.

Ahora, si intenta vincular esas dos unidades de compilación, por ejemplo, usando el siguiente comando:

⟩⟩⟩ g++ -std=c++11 -pedantic main.cpp test.cpp

Obtendrá un error que dice "símbolo duplicado __Z4meanRKNSt3__16vectorIdNS_9allocatorIdEEEE" (que es el nombre destrozado de nuestra función mean ).

Sin embargo, si descomenta el modificador en inline delante de la definición de la función, el código compila y enlaza correctamente.

Las plantillas de función son un caso especial: siempre están en línea, independientemente de si fueron declaradas de esa manera. Esto no significa que el compilador los llamará en línea, pero no violarán la ODR. Lo mismo es cierto para las funciones de miembro que se definen dentro de una clase o estructura.


"en línea" es como el equivalente al 2000 de "registrar". No se moleste, el compilador puede hacer un mejor trabajo al decidir qué optimizar que usted.


Al hacer una línea, el compilador inserta la implementación de la función en el punto de llamada. Lo que está haciendo con esto es eliminar la sobrecarga de llamada de función. Sin embargo, no hay garantía de que todos sus candidatos para la alineación estén en línea por el compilador. Sin embargo, para funciones más pequeñas, los compiladores siempre están en línea. Por lo tanto, si tiene una función que se llama muchas veces pero solo tiene una cantidad limitada de código, un par de líneas, puede beneficiarse de la alineación, porque la sobrecarga de llamada de función puede llevar más tiempo que la ejecución de la función en sí.

Un ejemplo clásico de un buen candidato para inline son getters para clases concretas simples.

CPoint { public: inline int x() const { return m_x ; } inline int y() const { return m_y ; } private: int m_x ; int m_y ; };

Algunos compiladores (p. Ej., El VC2005) tienen una opción de alineación agresiva, y no necesitarías especificar la palabra clave ''en línea'' cuando usas esa opción.


Depende del compilador ...
Digamos que tienes un compilador tonto. Al indicar que una función debe estar en línea, colocará una copia del contenido de la función en cada aparición si se llama.

Ventaja: sin sobrecarga de llamada de función (poner parámetros, empujar la PC actual, saltar a la función, etc.). Puede ser importante en la parte central de un gran ciclo, por ejemplo.

Inconveniencia: infla el binario generado.

¿Es una macro? En realidad, no, porque el compilador todavía verifica el tipo de parámetros, etc.

¿Qué hay de los compiladores inteligentes? Pueden ignorar la directiva en línea, si "sienten" que la función es demasiado compleja / demasiado grande. Y tal vez puedan alinear automáticamente algunas funciones triviales, como getters / setters simples.


El código en línea es más rápido. No es necesario realizar una llamada a función (cada llamada de función cuesta algo de tiempo). La desventaja es que no puede pasar un puntero a una función en línea, ya que la función no existe realmente como función y, por lo tanto, no tiene puntero. Además, la función no se puede exportar a público (por ejemplo, una función en línea en una biblioteca no está disponible dentro de los binarios que enlazan con la biblioteca). Otra es que la sección del código en su binario crecerá, si llama a la función desde varios lugares (como cada vez que se genera una copia de la función en lugar de tener una sola copia y saltar siempre)

Por lo general, no tiene que decidir manualmente si una función debe estar en línea o no. Por ejemplo, GCC lo decidirá automáticamente en función del nivel de optimización (-Ox) y de otros parámetros. Tomará en cuenta cosas como "¿Qué tan grande es la función?" (número de instrucciones), con qué frecuencia se llama dentro del código, cuánto se agrandará el binario al subrayarlo, y algunas otras métricas. Por ejemplo, si una función es estática (por lo tanto no se exporta de todos modos) y solo se llama una vez dentro de su código y nunca usa un puntero a la función, es probable que GCC decida alinearla automáticamente, ya que no tendrá un impacto negativo (el el binario no se hará más grande al incluirlo solo una vez).


El código en línea funciona en esencia como macros, pero es un código real real, que puede optimizarse. Las funciones muy pequeñas a menudo son buenas para enlining porque el trabajo necesario para configurar la llamada a la función (cargar los parámetros en los registros adecuados) es costoso en comparación con la pequeña cantidad de trabajo real que hace el método. Con Inline, no hay necesidad de configurar la llamada a la función, porque el código se "pega" directamente en cualquier método que lo use.

Inlinear aumenta el tamaño del código, que es su principal inconveniente. Si el código es tan grande que no cabe en la memoria caché de la CPU, puede sufrir ralentizaciones importantes. Solo debe preocuparse por esto en casos excepcionales, ya que no es probable que esté usando un método en tantos lugares que el código incrementado podría causar problemas.

En resumen, la alineación es ideal para acelerar los métodos pequeños que se llaman muchas veces, pero no en muchos lugares (100 lugares todavía están bien, sin embargo, es necesario entrar en ejemplos bastante extremos para obtener un aumento significativo del código).

Editar: como han señalado otros, incluir en línea es solo una sugerencia para el compilador. Puede ignorarlo libremente si cree que está haciendo solicitudes estúpidas como incluir un gran método de 25 líneas.


En general, la habilitación se habilita en el nivel 3 de optimización (-O3 en el caso de GCC). Puede ser una mejora de velocidad significativa en algunos casos (cuando es posible).

La inclusión explícita en sus programas puede agregar alguna mejora de velocidad con el costo de un tamaño de código adicional.

Debería ver cuál es el adecuado: el tamaño o la velocidad del código y decidir si debe incluirlo en sus programas.

Simplemente puede activar el nivel 3 de optimización y olvidarse de él, dejando que el compilador haga su trabajo.


En primer lugar, en línea es una solicitud al compilador para alinear la función. Así que está hasta el compilador para hacerlo en línea o no.

  1. Cuándo usar? Cuando alguna vez una función es de muy pocas líneas (para todos los accesorios y mutador) pero no para funciones recursivas
  2. Ventaja: el tiempo necesario para invocar la llamada de función no está involucrado
  3. ¿Es el compilador en línea cualquier función propia? Sí, siempre que una función esté definida en el archivo de encabezado dentro de una clase

Inline difiere de las macros en que es una pista para el compilador (¡el compilador puede decidir no insertar el código!) Y las macros son generación de texto de código fuente antes de la compilación y, como tales, son "forzadas" para ser inlineadas.


Inline es una técnica para aumentar la velocidad. Pero use un generador de perfiles para probar esto en su situación. He descubierto (MSVC) que la línea interna no siempre funciona, y ciertamente no de manera espectacular. Los tiempos de ejecución a veces disminuyeron en un pequeño porcentaje, pero en circunstancias ligeramente diferentes aumentaron en un pequeño porcentaje.

Si el código se ejecuta lentamente, salga de su generador de perfiles para encontrar los puntos problemáticos y trabaje en ellos.

Dejé de agregar funciones en línea a los archivos de encabezado, aumenta el acoplamiento pero da poco a cambio.


La respuesta de si en línea se reduce a la velocidad. Si estás en un círculo cerrado llamando a una función, y no es una función súper enorme, sino una en la que se desperdicia una gran cantidad de tiempo en LLAMAR a la función, entonces haz que esa función entre en línea y obtendrás una gran cantidad de tu dinero.


Marcar una función en línea significa que el compilador tiene la opción de incluir en "en línea", donde se llama, si el compilador elige hacerlo; por el contrario, una macro siempre se expandirá en el lugar. Una función incorporada tendrá símbolos de depuración apropiados configurados para permitir que un depurador simbólico rastree la fuente de donde vino, mientras que la depuración de macros es confusa. Las funciones en línea deben ser funciones válidas, mientras que las macros ... bueno, no.

Decidir declarar una función en línea es en gran medida una compensación de espacio: tu programa será más grande si el compilador decide alinearlo (particularmente si no es también estático, en cuyo caso se requiere al menos una copia no en línea para su uso por cualquier objeto externo); de hecho, si la función es grande, esto podría resultar en una caída en el rendimiento ya que menos de su código cabe en la memoria caché. Sin embargo, el impulso general en el rendimiento es que se está deshaciendo de la sobrecarga de la llamada a la función; para una pequeña función llamada como parte de un bucle interno, esa es una compensación que tiene sentido.

Si confía en su compilador, marque liberalmente las funciones pequeñas utilizadas en los bucles internos; el compilador será responsable de hacer lo correcto al decidir si alinear o no.


No voy a reiterar lo anterior, pero vale la pena señalar que las funciones virtuales no estarán en línea ya que la función llamada se resuelve en tiempo de ejecución.


Si está marcando su código como en línea en fe C ++ también le está diciendo a su compilador que el código debe ejecutarse en línea, es decir. ese bloque de código se insertará "más o menos" donde se llame (eliminando así el empuje, el estallido y el salto en la pila). Entonces, sí ... se recomienda si las funciones son adecuadas para ese tipo de comportamiento.


  • ¿Hay una gran diferencia entre el código "normal" y el código en línea?

Sí, el código en línea no implica una llamada a función y guarda variables de registro en la pila. Utiliza el espacio del programa cada vez que se ''llama''. Por lo tanto, en general lleva menos tiempo ejecutarlo, ya que no existe una bifurcación en el procesador y un ahorro de estado, eliminación de cachés, etc.

  • ¿El código en línea es simplemente una "forma" de macros?

Las macros y el código en línea comparten similitudes. la gran diferencia es que el código en línea está formateado específicamente como una función, por lo que el compilador y los mantenedores futuros tienen más opciones. Específicamente, puede convertirse fácilmente en una función si le dice al compilador que optimice el espacio del código, o un futuro mantenedor termina expandiéndolo y usándolo en muchos lugares en su código.

  • ¿Qué tipo de compensación debe hacerse al elegir alinear su código?

    • Macro: alto uso de espacio de código, ejecución rápida, difícil de mantener si la ''función'' es larga
    • Función: uso de espacio de código bajo, más lento de ejecutar, fácil de mantener
    • Función en línea: alto uso del espacio de código, ejecución rápida, fácil de mantener

Cabe señalar que el registro de guardar y saltar a la función ocupa espacio de código, por lo que para funciones muy pequeñas una línea puede ocupar menos espacio que una función.

-Adán