2009-07-06 47 views
6

Importante: Consulte esta pregunta muy relacionada: Return multiple values in C++.Devolver múltiples valores desde una función C

¿Cómo hago lo mismo en ANSI C? ¿Usarías una estructura o pasarías las direcciones de los params en la función? Busco un código extremadamente eficiente (rápido) (tiempo y espacio), incluso a costa de la legibilidad.

EDIT: Gracias por todas las respuestas. Ok, creo que debo alguna explicación: estoy escribiendo este libro sobre un cierto subconjunto de algoritmos para un dominio en particular. Me he marcado el objetivo bastante arbitrario de hacer que las implementaciones más eficientes (tiempo y espacio) para todos mis algos se coloquen en la web, a costa de la legibilidad y otras cosas. Esa es en parte la naturaleza de mi pregunta (general).

respuesta: espero aclarar esto, a partir de (posiblemente) más rápido a más de sentido común (todo esto a priori, es decir, sin pruebas):

  1. outvalues ​​en tienda a objeto global (I asumiría algo así como outvals [2]?), o
  2. outvalues ​​pasar como parametros en la función (foo (int en, int * OUT1, int * OUT2)), o
  3. retorno una estructura con dos outvals, o
  4. (3) solo si los valores están semánticamente relacionados.

¿Tiene esto sentido? Si es así, creo que la respuesta de Jason es la más cercana, a pesar de que todos proporcionan alguna pieza del "rompecabezas". Robert está bien, pero en este momento la semántica no es lo que busco (aunque su consejo está debidamente anotado)

Gracias a todos.

+3

Escriba su código y perfil despiadadamente. Creo que encontrará que el impacto en el rendimiento de struct-vs-reference es * tan minúsculo * en comparación con el resto de su implementación, que ni siquiera vale la pena tenerlo en cuenta. –

+0

Este es un buen consejo también. Gracias. (Por cierto, te suscribí, sucede que estaba buscando una respuesta mucho más práctica, eso es todo.) –

+0

Lo sé. Gracias. –

Respuesta

5

Como dice Neil, tiene que juzgar por sí mismo.

Para evitar el gasto de pasar nada, utilice un global. Lo mejor es una sola estructura pasada por puntero/referencia. Después de eso, son parámetros individuales de puntero/referencia.

Sin embargo, si tiene que empaquetar datos en la estructura y luego volver a leerlos después de la llamada, es mejor que pase parámetros individuales.

Si no está seguro, solo escriba un poco de código de prueba rápido usando ambos enfoques, ejecute cada uno unos cientos de miles de veces, y cítelos para ver cuál es el mejor.

3

Ha descrito las dos soluciones posibles y su limitación de rendimiento percibida. A dónde va desde aquí realmente depende de usted; no tenemos suficiente información para emitir un juicio informado.

+0

Entiendo. Acaba de comenzar C y quería saber si había una mejor manera. ¿Diría que las estructuras son más caras que la alternativa? –

+1

Para los editores: asegúrese de escribir su propia ortografía al hacer las correcciones. –

+0

@Dervin Probablemente no haya una diferencia enorme en el rendimiento entre las dos opciones, pero esto dependerá de cómo uses la estructura, etc. de la que no tenemos detalles. Si el rendimiento es tan importante (y, francamente, rara vez lo es), entonces debe realizar sus propias mediciones para averiguar cuál es el más rápido. –

1

El modo más rápido Q & D que puedo pensar es pasar los valores en un objeto global, de esta manera se salta la operación de pila, pero tenga en cuenta que no será seguro para subprocesos.

+1

No necesariamente, si los objetos globales deben ser captados en la caché. –

0

Pasaría la dirección a una estructura. Si la información que debe devolverse no es compleja, entonces el solo hecho de pasar las direcciones a los valores también funcionaría.

Personalmente, realmente se reduce a lo desordenada que sería la interfaz.

void SomeFunction(ReturnStruct* myReturnVals) 
{ 
    // Fill in the values 
} 

// Do some stuff  
ReturnStruct returnVals; 
SomeFunction(&returnVals);  
// Do more stuff 
+0

Disculpe mi ignorancia, todavía no sé mucho sobre C. ¿Por qué es malo devolver una copia local de la estructura? –

+0

Acutalmente, no estaría mal, siempre que no esté apuntando a la memoria asignada dentro de la función. Solo voy a quitar ese bloque para reducir la confusión. –

+0

@Soo Wei Tan - no, tenías razón acerca de la memoria asignada dentro de la función (y esto es malo) - no necesitas quitarla, se trata de entrenar para hacer las cosas bien. – KevinDTimm

7

Ambas formas son válidas, certianly, pero yo se considerar la semántica (struct vs parámetro de referencia) para decidir la forma en que se comunica mejor intenciones para el programador.

Si los valores que está devolviendo están estrechamente acoplados, entonces está bien devolverlos como una estructura. Pero, si simplemente está creando mecanismo artificial para devolver valores juntos (como una estructura), entonces debe usar una referencia de parámetro (es decir, pasar la dirección de las variables) para devolver los valores a la función de llamada.

Enjoy,

Robert C. Cartaino

3

más fácil de leer debe ser pasado direcciones en la función, y debe ser rápido también, pops y empujones son baratos:

void somefunction (int inval1, int inval2, int *outval1, int *outval2) { 
    int x = inval1; 
    int y = inval2; 
// do some processing 
    *outval1 = x; 
    *outval2 = y; 
    return; 
} 
+0

¿Quiere decir & outval1, int & outval2? –

+3

no. Escribí exactamente lo que quise decir. – KevinDTimm

+0

está bien, pero por favor resalte su código – mtasic85

0

Esto depende enormemente de su arquitectura, y también si espera (o puede tener) la función en línea. Primero escribo el código de la manera más simple, y luego me preocupo por la velocidad si eso aparece como una parte costosa de tu código.

1

Creo que cuando devuelve un puntero de estructura, probablemente necesite encontrar algo de memoria para eso. Las direcciones en la lista de parámetros se asignan en la pila, que es mucho más rápida.

0

En cualquier caso, está aprobando referencias, por lo que el rendimiento debería ser similar. Si existe la posibilidad de que la función nunca devuelva un valor, puede evitar el costo del malloc con la opción "devolver una estructura", ya que simplemente devolverá un valor nulo.

Mi preferencia personal es devolver una estructura dinámicamente asignada (malloc'd). Evito usar argumentos de función para el resultado porque creo que hace que el código sea más confuso y menos sostenible a largo plazo.

+0

Asignado dinámicamente significa potencial de pérdida de memoria como mínimo. Eso significa que los usuarios de su función deben ser mucho más cuidadosos. –

1

Tenga en cuenta que a veces es más rápido pasar parámetros por valor y actualizar al volver (o hacer copias locales en la pila) que por referencia ... Esto es muy evidente con estructuras pequeñas o pocos parámetros y muchos accesos.

-1

Devolver una copia local de la estructura es malo porque si la estructura se declaró no estática dentro de la función, se vuelve nula cuando se sale de la función.

Y a todas las personas que sugieren referencias, el OP dijo "C" y C no las tiene (referencias).

Y dulce plumaje Jesús, ¿puedo levantarme mañana y no tener que ver nada sobre el Rey del fracaso en la televisión?

Cuestiones relacionadas