valores valor retornar retornan retorna referencia recibe que programacion parametros intercambio funciones funcion devuelven c++ c struct return-value-optimization copy-elision

c++ - retornar - Optimización del valor de retorno y copia de elisión en C



retornar dos valores en c (2)

Algunas personas no son conscientes de que es posible pasar y devolver estructuras por valor en C. Mi pregunta es sobre el compilador que hace copias innecesarias cuando devuelve estructuras en C. ¿Los compiladores de C como GCC usan la optimización de valor de retorno (RVO) o es un concepto exclusivo de C ++? Todo lo que he leído sobre RVO y copia de elisión se refiere a C ++.

Consideremos un ejemplo. Actualmente estoy implementando un tipo de datos doble-doble en C (o más bien float-float para empezar porque me resulta fácil realizar pruebas unitarias). Considere el siguiente código.

typedef struct { float hi; float lo; } doublefloat; doublefloat quick_two_sum(float a, float b) { float s = a + b; float e = b - (s - a); return (doublefloat){s, e}; }

¿El compilador realizará una copia temporal del valor de doublefloat que devuelvo o se puede doublefloat la copia temporal?

¿Qué pasa con la optimización del valor de retorno con nombre (NRVO) en C? Tengo otra funcion

doublefloat df64_add(doublefloat a, doublefloat b) { doublefloat s, t; s = two_sum(a.hi, b.hi); t = two_sum(a.lo, b.lo); s.lo += t.hi; s = quick_two_sum(s.hi, s.lo); s.lo += t.lo; s = quick_two_sum(s.hi, s.lo); return s; }

En este caso, estoy devolviendo una estructura con nombre. ¿Puede la copia temporal en este caso ser anulada?

Cabe señalar que esta es una pregunta general para C y que los ejemplos de código que he usado aquí son solo ejemplos (cuando optimice esto, usaré SIMD con intrínsecos de todos modos). Soy consciente de que podría mirar el resultado del ensamblaje para ver qué hace el compilador, pero creo que esta es una pregunta interesante.


La razón por la que está cubierto mucho para C ++ es porque en C ++, RVO tiene efectos secundarios (es decir, no llama al destructor de los objetos temporales ni al constructor de copias ni al operador de asignación de los objetos resultantes).

En C, no hay efectos secundarios posibles, solo mejoras de rendimiento potenciales. No veo ninguna razón para que un compilador no pueda realizar tal optimización. Al menos, no hay nada que lo prohíba en el estándar.

De todos modos, la optimización depende del compilador y del nivel de optimización, por lo que no apostaría por rutas de código críticas, a menos que el compilador utilizado esté bien definido y no se espere que cambie (que a menudo es el caso).


RVO / NRVO están claramente permitidos bajo la regla "como si" en C.

En C ++ puede obtener efectos secundarios observables porque ha sobrecargado el constructor, el destructor y / o el operador de asignación para dar esos efectos secundarios (por ejemplo, imprimir algo cuando ocurre una de esas operaciones), pero en C no tienen la capacidad de sobrecargar a esos operadores, y los incorporados no tienen efectos secundarios observables.

Sin sobrecargarlos, no obtiene efectos secundarios observables de la copia de elisión y, por lo tanto, nada para evitar que un compilador lo haga.