Por ejemplo, las funciones serían:
void foo(float*,float*,int,float); void foo(float*,float,float*,int);tienen gastos generales iguales o diferentes?
Editar: no estoy preguntando cómo el compilador optimizará las cosas. Estoy preguntando específicamente en relación con la convención de llamadas cdecl cómo los gastos generales serán diferentes en varios ABI.
Por supuesto, este tipo de detalle depende de la plataforma/ABI.
Por ejemplo, con x86-64 no debería haber diferencia, ya que estos pocos parámetros se pasarían simplemente en registros y el uso de registros es casi simétrico (por lo que realmente no importa qué registro desea usar).
Con más parámetros, habría un derrame de pila y, en este caso, podría marcar la diferencia dependiendo de cómo se usen los parámetros derramados en el cuerpo de la función.
Por ejemplo, si se necesitan como un conteo para un bucle, entonces se pueden usar directamente desde la pila; si, en cambio, son punteros, para desreferenciar el valor señalado, primero se deben mover a un registro.
Tenga en cuenta que, por supuesto, lo que sucede exactamente depende del compilador (incluso con solo dos parámetros) ... por lo que no es imposible que haya diferencias; lo que es imposible es usar un orden específico para obtener un mejor resultado en general (es decir, independientemente del compilador).
Las convenciones de llamadas tradicionales casi siempre asignan espacio de parámetros en la pila, y siempre hay una sobrecarga asociada con la copia de argumentos en este espacio.
Suponiendo un entorno estrictamente volátil, la única sobrecarga adicional que puede existir potencialmente puede surgir de problemas de alineación de la memoria. En su ejemplo dado, los parámetros estarán en la memoria contigua y, por lo tanto, no habrá ningún relleno para alinear correctamente.
En el caso de parámetros con tipos de diferentes tamaños, los parámetros en la siguiente declaración:
int func (int a, char c, int b)tendrán relleno entre ellos, mientras que los de esta declaración:
int func (int a, int b, char c)no lo haré
El marco de pila para el primero podría verse así:
| local vars... | low memory +---------------+ - frame pointer | a | a | a | a | | c | X | X | X | | b | b | b | b | +---------------+ high memoryY para este último:
| local vars... | low memory +---------------+ - frame pointer | a | a | a | a | | b | b | b | b | | c | X | X | X | +---------------+ high memory Cuando se llama a la función, los argumentos se escribirán en la memoria de la pila en el orden en que aparecen, por lo que para el primero escribirá los 4 bytes de int a , el 1 byte de char c , luego debe omitir esos 3 bytes para escribir los 4 bytes de int b .
En este último, escribirá en ubicaciones de memoria contiguas y no necesitará tener en cuenta los saltos debido al relleno.
En un entorno volátil, estamos hablando de una diferencia en el rendimiento del orden de varios nanosegundos para los saltos. El impacto en el rendimiento puede ser detectable pero casi insignificante.
(Por cierto, la forma en que se salta depende completamente de la arquitectura... pero apuesto a que, en general, es solo un desplazamiento más alto para que se llene la siguiente dirección. No estoy completamente seguro de cómo se podría hacer esto de manera diferente en diferentes arquitecturas).
Por supuesto, en un entorno no volátil, cuando utilizamos el almacenamiento en caché de la CPU, el impacto en el rendimiento se reduce a fracciones de nanosegundo. Estaríamos aventurándonos en lo indetectable, por lo que la diferencia es efectivamente inexistente.
El relleno de datos es realmente solo un costo de espacio . Cuando trabaje en sistemas integrados, querrá ordenar sus parámetros de mayor a menor para reducir (ya veces eliminar) el relleno.
Entonces, por lo que puedo decir (sin más información, como las tasas exactas de transferencia de datos entre la memoria en una máquina o arquitectura en particular), no debería haber un impacto en el rendimiento para diferentes órdenes de parámetros.