Test Foro de elhacker.net SMF 2.1

Programación => Programación C/C++ => Mensaje iniciado por: samur88 en 16 Mayo 2011, 15:27 PM

Título: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: samur88 en 16 Mayo 2011, 15:27 PM
Hola, tengo la siguiente duda:

En una funcion convierto los punteros void según lo necesite, es decir según el que le pase, lo que no se si es esto es una practica aceptada en C, compilar y funcionar funciona pero no se si debe hacer o no, o hacer esto puede acarrear fallos en algunos programas.
Me gustaría saber si es algo así como una practica que se puede hacer pero que debe evitarse en el mayor de los casos.

Esta es la función, lo que hago es convertir al tipo "medicos" o "pacientes" dependiendo de si "opc" es 0 u 1.
Al hacer la llamada solo el puntero que le pase a la función puede ser tanto del tipo
"medicos" como del "pacientes".
bool val_dni(void *primero,int dni,bool opc){
    medicos *auxM;
    pacientes *auxP;
    int m = 0;
    int p = 0;
    /* 0 para medicos, 1 para pacientes.
       0 si no existe, 1 si existe.   
    */
   
    if(opc == 1){
               
           auxP = (pacientes *)primero;
           while(auxP != NULL){
                        if(auxP->dni == dni){ return 1; }
                        auxP = auxP->next;
                     }
           return 0;
    }else{
          auxM = (medicos *)primero;
          while(auxM != NULL){
                        if(auxM->dni == dni){return 1; }
                        auxM = auxM->next;
                     }
          return 0;
    }
}


Un saludo.
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: Queta en 16 Mayo 2011, 18:09 PM
CitarThe void type of pointer is a special type of pointer. In C++, void represents the absence of type, so void pointers are pointers that point to a value that has no type (and thus also an undetermined length and undetermined dereference properties).

This allows void pointers to point to any data type, from an integer value or a float to a string of characters. But in exchange they have a great limitation: the data pointed by them cannot be directly dereferenced (which is logical, since we have no type to dereference to), and for that reason we will always have to cast the address in the void pointer to some other pointer type that points to a concrete data type before dereferencing it.

http://www.cplusplus.com/doc/tutorial/pointers/ (http://www.cplusplus.com/doc/tutorial/pointers/)
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: samur88 en 16 Mayo 2011, 18:54 PM
Muchas gracias, no estoy seguro de haberlo entendido bien, pero creo que es algo así como que lo puedo usar para punteros que apunten a un dato el cual yo no voy a modificar desde una función, si no solo a comprobar su valor, como en mi caso, pero no podría usarlo por ejemplo para punteros que apuntaran a otro puntero con el fin de modificar el valor de este ultimo.

¿Lo he entendido bien?

Un saludo.
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: pucheto en 16 Mayo 2011, 20:40 PM
Si, se pueden usar asi, no esta mal... Pero hay mejores ideas, como usar una struct con una union y con un flag q te indique el tipo.
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: samur88 en 16 Mayo 2011, 22:40 PM
Muchas gracias, ¿como es eso  :D? ¿Podrías ponerme un ejemplo por favor?
Mas o menos me situó pero no se como picar el código xD

Quieres decir una estructura con un enum dentro que contendría dos elementos, médicos y pacientes, ¿no? ¿Pero como hago para saber el tipo?
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: pucheto en 17 Mayo 2011, 04:12 AM
Cita de: samur88 en 16 Mayo 2011, 22:40 PM
Quieres decir una estructura con un enum dentro que contendría dos elementos, médicos y pacientes, ¿no? ¿Pero como hago para saber el tipo?
Casi! un enum para indicar el tipo, y despues una union con puntero a medico y un puntero a paciente, y segun sea se usa uno u el otro elegis cual usas ( la union solo sirve para no andar haciendo casts, y el puntero a medico y a paciente ocuparian el mismo espacio de memoria... si lees un poco mas de uniones vas a entender q es lo q digo )
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: samur88 en 17 Mayo 2011, 19:54 PM
Gracias, ¿sería algo así?:

struct punteros_l {
medicos *primeroM;
pacientes *primeroP;
}

union punteros_l punteros;

enum opcion (0 = punteros.primeroM,1 = punteros.primeroP);

Es que me parece muy interesante lo que dices y quiero llegar a comprenderlo.
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: pucheto en 18 Mayo 2011, 04:56 AM

union {
    medicos* m;
    pacientes* p;
}p_e;

struct persona {
    p_e data;
    tipo_persona flag;
} personaHospital;


pseudocodigo...


personaHospital p = /*... hago lo q tengo q hacer, inicializo y demas*/

switch(p.flag){
    case f_medico:
         //lo manejo como medico
        handleMedico(m.data.m);
        break;
    case f_paciente:
         //lo manejo como paciente
        handlePaciente(m.data.p);
        break;
}


me falto definir el enum tipo_persona, pero se entiende masomenos... No esperes q compile, es pseudocodigo puesto asi nomas para ejemplificar.
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: samur88 en 18 Mayo 2011, 20:50 PM
Muchas gracias, pero ¿el enum para que serviría?
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: pucheto en 18 Mayo 2011, 21:46 PM
Para indicar q puntero tenes q usar... y distinguir si es paciente o medico...
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: D4RIO en 19 Mayo 2011, 16:24 PM
Obviamente, debes conocer las diferencias de tamaños para decidir si una union es buena idea o no, y saber si realmente necesitas ese almacenamiento. En ESTA situación, cualquier uso de uniones es DISPARATADO  ;D

¿Porqué?
Porque cuando aún no sabes si es un médico o un paciente, usas el flag para tratarlo. Entonces ¿realmente necesitas almacenar las estructuras en un espacio de memoria común? Sin importar el tipo, puedes tener dos funciónes diferentes, con lo que la función que hace de dispatcher, no tiene que hacer más que pasar el puntero a quien le corresponda... que me parece mucho más razonable  ;), y si quieres probar si es NULL, lo haces al principio, cosa que te quedaría como:

void
funcion_dispatcher(void *puntero, tipo_dispatcher flag) {
    if (!puntero)
        muere("funcion_dispatcher: puntero nulo!");

    switch (flag) {
        case esMedico:
            funcionMedico((struct medico*)puntero);
            break;
        case esPaciente:
            funcionPaciente((struct paciente*)puntero);
            break;
    }
}


O lo que me parece más visible/lindo:
void
funcion_dispatcher(void *puntero, tipo_dispatcher flag) {
    if (!puntero)
        muere("funcion_dispatcher: puntero nulo!");

    if (flag == esMedico)
            funcionMedico((struct medico*)puntero);

    if (flag == esPaciente)
            funcionPaciente((struct paciente*)puntero);
}


Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: pucheto en 19 Mayo 2011, 17:16 PM
Cita de: xD4RIOx en 19 Mayo 2011, 16:24 PM
Obviamente, debes conocer las diferencias de tamaños para decidir si una union es buena idea o no, y saber si realmente necesitas ese almacenamiento. En ESTA situación, cualquier uso de uniones es DISPARATADO  ;D
Estoy usando una union de punteros, no de structs... todos los punteros ocupan lo mismo, no hay ningun desperdicio de espacio (al menos q sean near, far etc, pero eso ya depende mucho del sistema y es raro encontrarlo en la programacion en modo usuario).

Cita de: xD4RIOx en 19 Mayo 2011, 16:24 PM
¿Porqué?
Porque cuando aún no sabes si es un médico o un paciente, usas el flag para tratarlo. Entonces ¿realmente necesitas almacenar las estructuras en un espacio de memoria común?
Sin importar el tipo, puedes tener dos funciónes diferentes, con lo que la función que hace de dispatcher, no tiene que hacer más que pasar el puntero a quien le corresponda... que me parece mucho más razonable  ;), y si quieres probar si es NULL, lo haces al principio, cosa que te quedaría como....
Guardo el flag, con la union de punteros pq estan asociados, estan muy relacionados... Como estan tan relacionados, los pongo en el mismo struct...
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: D4RIO en 19 Mayo 2011, 18:23 PM
Cita de: pucheto en 19 Mayo 2011, 17:16 PM
Estoy usando una union de punteros, no de structs... todos los punteros ocupan lo mismo, no hay ningun desperdicio de espacio (al menos q sean near, far etc, pero eso ya depende mucho del sistema y es raro encontrarlo en la programacion en modo usuario).
Guardo el flag, con la union de punteros pq estan asociados, estan muy relacionados... Como estan tan relacionados, los pongo en el mismo struct...
No había visto lo de los punteros. Pero no quita lo que decía, porque usar un "union" donde siempre se usará un puntero, y acceder luego a sus miembros es a fin de cuentas... un casteo. Y si vamos a hacer un casteo es mejor ser explícitos.

Por otro lado, no están más relacionados de lo que significa pasar por un mismo dispatcher, porque al final serán tratados por funciónes diferentes. Como al fin y al cabo, usas el union para "castear" el puntero contenido en ese espacio de memoria (el union)...
switch(p.flag){
    case f_medico:
         //lo manejo como medico
        handleMedico(m.data.m);
        break;
    case f_paciente:
         //lo manejo como paciente
        handlePaciente(m.data.p);
        break;
}

...entonces resulta más legible ir al grano con un cast. A demás, al usar esta forma tienes dos problemas a tener en cuenta:

1 - Necesitas una variable extra en la pila local de la función... solo a fin de alojar el puntero que te llega por parámetro, y para enviarlo a otra función. Es innecesario.
2 - Si declaras desde el main los datos como instancias de la union para evitar las variables locales innecesarias, pierdes la posibilidad de tener flujos donde se manejen solo pacientes, o solo médicos (en el ejemplo), sin pasar previamente por un dispatcher. Si los dispatchers son siempre necesarios, es porque tienes dos flujos separados. Seguramente perderás más de dos bytes haciendo dispatchers para cada flujo, y es la diferencia entre crear una instancia de cada tipo, y una union.

Si se desea castear un puntero, entonces se usa un cast, solo por mantener el código simple.

Saludos
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: pucheto en 19 Mayo 2011, 18:56 PM
Cita de: xD4RIOx en 19 Mayo 2011, 18:23 PM
1 - Necesitas una variable extra en la pila local de la función... solo a fin de alojar el puntero que te llega por parámetro, y para enviarlo a otra función. Es innecesario.
Una cosa que no veo aca, hagas como hagas, si o si vas a tener que pasarle el puntero a la otra funci\'on. No veo donde esta el problema. En tu codigo tambien tenes que pasar el puntero a una funcion.

Cita de: xD4RIOx en 19 Mayo 2011, 18:23 PM
2 - Si declaras desde el main los datos como instancias de la union para evitar las variables locales innecesarias, pierdes la posibilidad de tener flujos donde se manejen solo pacientes, o solo médicos (en el ejemplo), sin pasar previamente por un dispatcher. Si los dispatchers son siempre necesarios, es porque tienes dos flujos separados. Seguramente perderás más de dos bytes haciendo dispatchers para cada flujo, y es la diferencia entre crear una instancia de cada tipo, y una union.

Si se desea castear un puntero, entonces se usa un cast, solo por mantener el código simple.

Saludos
Tampoco veo pq se pierde la posibilidad de tener secciones donde solo se manejan solo medicos o solo pacientes.

Si podes pone un ejemplo donde se vea mejor.
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: samur88 en 19 Mayo 2011, 21:07 PM
Una cosa, que me he liado, entonces que sería mas optimo hacer el cast directamente o hacer lo que propone pucheto mediante uniones y estructuras.

Un saludo y gracias por las respuestas.
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: D4RIO en 19 Mayo 2011, 21:25 PM
El cast directamtnte es mejor.


Cita de: pucheto en 19 Mayo 2011, 18:56 PM
Una cosa que no veo aca, hagas como hagas, si o si vas a tener que pasarle el puntero a la otra funci\'on. No veo donde esta el problema. En tu codigo tambien tenes que pasar el puntero a una funcion.
No fue lo que expuse. La diferencia, aclaro, es que necesitas una variable local para usar la union.

Cita de: pucheto en 19 Mayo 2011, 18:56 PM
Tampoco veo pq se pierde la posibilidad de tener secciones donde solo se manejan solo medicos o solo pacientes.

Si podes pone un ejemplo donde se vea mejor.
Este sería el otro caso. Si no usas una variable local, pasas las uniones desde que las creas... probablemente desde el main. Entonces, si una función o grupo de funciones trabajan con "struct paciente", necesitas una funcion intermediaria (un dispatcher), que les pase el puntero. Eso significa una funcion para adaptar a cada flujo que use solo una estructura, cosa que no pasaría si las estructuras fueran siempre diferentes. Solo los flujos que aceptan ambos tipos necesitan el dispatcher.

Saludos
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: Littlehorse en 19 Mayo 2011, 23:49 PM
Dependiendo el problema depende que solución es mas aceptable, y esto ultimo siempre va a ser subjetivo. Personalmente para este caso en particular me parece mas correcta la idea de Pucheto que hacer un cast directo. Tal vez las ventajas del planteo de Pucheto no son tan visibles en 10 lineas pero se notarían si tenes que ponerte al día en un proyecto relativamente extenso y encima mantenerlo, aunque esto por supuesto depende de cada uno.

Saludos
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: pucheto en 20 Mayo 2011, 03:10 AM
Cita de: xD4RIOx en 19 Mayo 2011, 21:25 PM
El cast directamtnte es mejor.

No fue lo que expuse. La diferencia, aclaro, es que necesitas una variable local para usar la union.
Este sería el otro caso. Si no usas una variable local, pasas las uniones desde que las creas... probablemente desde el main. Entonces, si una función o grupo de funciones trabajan con "struct paciente", necesitas una funcion intermediaria (un dispatcher), que les pase el puntero. Eso significa una funcion para adaptar a cada flujo que use solo una estructura, cosa que no pasaría si las estructuras fueran siempre diferentes. Solo los flujos que aceptan ambos tipos necesitan el dispatcher.

Saludos
Del 1er punto sigo sin ver que variable local uso...
Del punto 2, si una funcion trabaja con un paciente solamente, le paso el puntero al paciente, no toda el struct con el flag... el struct con el flag solamente lo uso cuando tenga q manejar de manera generica a medicos y pacientes por igual, y tal vez aplicarle alguna funcion generica que necesite tratarlos de maneras distintas. Depende mucho del contexto de uso todo esto.
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: D4RIO en 20 Mayo 2011, 03:46 AM
Esto ya es un mareo. A ver:
Cita de: Littlehorse en 19 Mayo 2011, 23:49 PM
Dependiendo el problema depende que solución es mas aceptable, y esto ultimo siempre va a ser subjetivo. Personalmente para este caso en particular me parece mas correcta la idea de Pucheto que hacer un cast directo. Tal vez las ventajas del planteo de Pucheto no son tan visibles en 10 lineas pero se notarían si tenes que ponerte al día en un proyecto relativamente extenso y encima mantenerlo, aunque esto por supuesto depende de cada uno.

Supongo que será por lo relativo, pero yo, siendo nuevo en un proyecto, preferiría mil veces encontrar esto:
    if (flag == esMedico)
            funcionMedico((struct medico*)puntero);

    if (flag == esPaciente)
            funcionPaciente((struct paciente*)puntero);


que es explícito en lo que hace, y no esto:
    case f_medico:
        //lo manejo como medico
        handleMedico(m.data.m);
        break;
    case f_paciente:
        //lo manejo como paciente
        handlePaciente(m.data.p);
        break;


que es como... poco claro, a mi parecer.


Cita de: pucheto en 20 Mayo 2011, 03:10 AM
Del 1er punto sigo sin ver que variable local uso...
Si no lo entiendo mal, recibes un puntero en la función, y haces algo como:
Código (cpp) [Seleccionar]
void
funcion(void *punt ...) {
    personaHospital p = (personaHospital) *punt; /* algo asi, que requiere una variable local p, o un puntero */

    switch(p.flag){
        case f_medico:
            //lo manejo como medico
            handleMedico(m.data.m);
            break;
        case f_paciente:
            //lo manejo como paciente
            handlePaciente(m.data.p);
            break;
    }
}


Que no era necesaria sin la union...

Cita de: pucheto en 20 Mayo 2011, 03:10 AM
Del punto 2, si una funcion trabaja con un paciente solamente, le paso el puntero al paciente, no toda el struct con el flag... el struct con el flag solamente lo uso cuando tenga q manejar de manera generica a medicos y pacientes por igual, y tal vez aplicarle alguna funcion generica que necesite tratarlos de maneras distintas. Depende mucho del contexto de uso todo esto.
Creo que nunca se manejarían "por igual"... si tuvieran miembros en común que se manejen por igual, entonces metería algo como herencia. Una estructura compartida entre ambos al inicio de la estructura de cada uno. Y así los despachos con un único puntero siguen siendo válidos, aunque en realidad habrá código compartido tanto como código para cada implementación.

Estamos tratando de dar solución a ningún problema, creo que eso es lo más confuso  :)

Muestrame el código que pondrías para darme una mejor idea de tu idea.

Saludos
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: pucheto en 20 Mayo 2011, 04:01 AM
Ta, estabamos pensando distinto el problema... Yo suponia que el tipo 'personaHospital' venia ya de arriba, pq lo crea una funcion o algo asi... mi funcion con la version que yo proponia era tomar directamente el struct personaHospital, y no un puntero para despues convertirlo.

Mi idea era hacerlo algo similar a herencia.
Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: Littlehorse en 20 Mayo 2011, 04:11 AM
CitarSupongo que será por lo relativo, pero yo, siendo nuevo en un proyecto, preferiría mil veces encontrar esto:
No siempre ser explicito facilita el uso para el resto u para vos mismo. A mi por lo menos me queda mucho mas sencillo tomarme 5 minutos en ver como están implementadas las estructuras y ver de que se trata la unión que realizar casteos explícitos a cada segundo. Obviamente si sos nuevo en un proyecto tampoco te vas a meter en el comportamiento interno de una función sin ver como están implementadas sus entidades básicas, claro esta.

Tu planteo no es invalido, pero obviamente eso no lo hace el mejor ni el mas correcto para todos los casos. La idea de Pucheto no es nueva y se suele usar bastante. A fin de cuentas es cuestión de gustos.

Saludos

Título: Re: ¿Es normal hacer este tipo de conversiones de punteros void?
Publicado por: D4RIO en 20 Mayo 2011, 04:21 AM
CitarObviamente si sos nuevo en un proyecto tampoco te vas a meter en el comportamiento interno de una función sin ver como están implementadas sus entidades básicas, claro esta.
jeje... cómo quisiera que sea así siempre, me ha tocado cada cosaa  :¬¬

Saludos!